Dynaview: Add support for saving/restoring scroll position from local storage

This commit is contained in:
Jermolene 2019-03-04 16:59:39 +00:00
parent 348a0bc8bc
commit a9e595c3f6
3 changed files with 57 additions and 6 deletions

View File

@ -0,0 +1,2 @@
title: $:/config/DynaView/RestoreScrollPositionAtStartup
text: yes

View File

@ -13,12 +13,18 @@ The components of this plugin include:
! Scroll Features
!! Scroll Position Preservation
!! Scroll position preservation during refresh
Some recent browsers have a feature called "scroll anchoring" whereby they suppress the apparent scrolling that occurs when elements are inserted or removed above the current viewport. (See https://github.com/WICG/ScrollAnchoring for more details).
~DynaView can optionally polyfill this behaviour for older browsers by setting the configuration tiddler $:/config/DynaView/PreserveScrollPosition to `yes`.
!! Startup scroll position restoration
Optionally, ~DynaView can store the current scroll position in local storage and restore it upon startup. Set the configuration tiddler $:/config/DynaView/RestoreScrollPositionAtStartup to `yes`.
Note that it is not recommended to use this setting at the same time as the "UpdateAddressBar" option.
!! Set tiddler field when visible
The background task detects when elements with the class `tc-dynaview-set-tiddler-when-visible` scroll into view. The first time that they do, the background task assigns the value in the attribute `data-dynaview-set-value` to the tiddler whose title is in the attribute `data-dynaview-set-tiddler`. This assignment can be tied to a reveal widget to cause content to be displayed when it becomes visible. If the class `tc-dynaview-expand-viewport` is set then the viewport is expanded so that the processing occurs when elements move near the viewport.
@ -29,7 +35,9 @@ The background task detects when elements with the class `tc-dynaview-set-tiddle
!! Update address bar when scrolling
The background task detects the tiddler at the top of the viewport and sets the address bar location hash to the title of that tiddler.
If the configuration tiddler $:/config/DynaView/UpdateAddressBar is set to `yes` the background task detects the tiddler at the top of the viewport and sets the address bar location hash to the title of that tiddler.
Note that it is not recommended to use this setting at the same time as the "RestoreScrollPositionAtStartup" option.
! Viewport Size Features

View File

@ -15,7 +15,7 @@ Zoom everything
// Export name and synchronous status
exports.name = "dynaview";
exports.platforms = ["browser"];
exports.after = ["render"];
exports.before = ["story"];
exports.synchronous = true;
var isWaitingForAnimationFrame = 0, // Bitmask:
@ -23,22 +23,33 @@ var isWaitingForAnimationFrame = 0, // Bitmask:
ANIM_FRAME_CAUSED_BY_SCROLL = 2, // Animation frame was requested because of page scroll
ANIM_FRAME_CAUSED_BY_RESIZE = 4; // Animation frame was requested because of window resize
var LOCAL_STORAGE_KEY_PREFIX = "tw5-dynaview-scroll-position#";
var hasRestoredScrollPosition = false;
exports.startup = function() {
var topmost = null, lastScrollY;
$tw.boot.disableStartupNavigation = true;
window.addEventListener("load",onLoad,false);
window.addEventListener("scroll",onScroll,false);
window.addEventListener("resize",onResize,false);
$tw.hooks.addHook("th-page-refreshing",function() {
if(shouldPreserveScrollPosition()) {
if(!hasRestoredScrollPosition) {
topmost = restoreScrollPosition();
} else if(shouldPreserveScrollPosition()) {
topmost = findTopmostTiddler();
}
lastScrollY = window.scrollY;
});
$tw.hooks.addHook("th-page-refreshed",function() {
if(lastScrollY === window.scrollY) { // Don't do scroll anchoring if the scroll position got changed
scrollToTiddler(topmost);
if(shouldPreserveScrollPosition() || !hasRestoredScrollPosition) {
scrollToTiddler(topmost);
hasRestoredScrollPosition = true;
}
}
updateAddressBar();
saveScrollPosition();
checkVisibility();
saveViewportDimensions();
});
@ -71,6 +82,7 @@ function worker() {
}
setZoomClasses();
updateAddressBar();
saveScrollPosition();
checkVisibility();
isWaitingForAnimationFrame = 0;
}
@ -157,11 +169,40 @@ function updateAddressBar() {
}
}
function saveScrollPosition() {
if(hasRestoredScrollPosition && $tw.wiki.getTiddlerText("$:/config/DynaView/RestoreScrollPositionAtStartup") === "yes") {
var top = findTopmostTiddler();
if(top.element) {
try {
window.localStorage.setItem(LOCAL_STORAGE_KEY_PREFIX + window.location.pathname,JSON.stringify({
title: top.title,
offset: top.offset
}));
} catch(e) {
console.log("Error setting local storage",e)
}
}
}
}
function restoreScrollPosition() {
var str = window.localStorage.getItem(LOCAL_STORAGE_KEY_PREFIX + window.location.pathname),
json;
if(str) {
try {
json = JSON.parse(str);
} catch(e) {
// Ignore errors
};
}
return json;
}
/*
tiddlerDetails: {title: <title of tiddler to scroll to>, offset: <offset in pixels from the top of the tiddler>}
*/
function scrollToTiddler(tiddlerDetails) {
if(shouldPreserveScrollPosition() && !$tw.pageScroller.isScrolling() && tiddlerDetails) {
if(!$tw.pageScroller.isScrolling() && tiddlerDetails) {
var elements = document.querySelectorAll(".tc-tiddler-frame[data-tiddler-title]"),
topmostTiddlerElement = null;
$tw.utils.each(elements,function(element) {