mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-27 03:57:21 +00:00
DynaView plugin: add optional scroll position preservation
This commit is contained in:
parent
af9f90e8cd
commit
e14e69bedc
@ -71,9 +71,10 @@ exports.startup = function() {
|
|||||||
timerId;
|
timerId;
|
||||||
function refresh() {
|
function refresh() {
|
||||||
// Process the refresh
|
// Process the refresh
|
||||||
|
$tw.hooks.invokeHook("th-page-refreshing");
|
||||||
$tw.pageWidgetNode.refresh(deferredChanges);
|
$tw.pageWidgetNode.refresh(deferredChanges);
|
||||||
deferredChanges = Object.create(null);
|
deferredChanges = Object.create(null);
|
||||||
$tw.hooks.invokeHook("th-page-refreshed");
|
$tw.hooks.invokeHook("th-page-refreshed");
|
||||||
}
|
}
|
||||||
// Add the change event handler
|
// Add the change event handler
|
||||||
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {
|
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {
|
||||||
|
@ -33,6 +33,10 @@ var PageScroller = function() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PageScroller.prototype.isScrolling = function() {
|
||||||
|
return this.idRequestFrame !== null;
|
||||||
|
}
|
||||||
|
|
||||||
PageScroller.prototype.cancelScroll = function(srcWindow) {
|
PageScroller.prototype.cancelScroll = function(srcWindow) {
|
||||||
if(this.idRequestFrame) {
|
if(this.idRequestFrame) {
|
||||||
this.cancelAnimationFrame.call(srcWindow,this.idRequestFrame);
|
this.cancelAnimationFrame.call(srcWindow,this.idRequestFrame);
|
||||||
|
15
editions/dev/tiddlers/new/Hook_ th-page-refreshing.tid
Normal file
15
editions/dev/tiddlers/new/Hook_ th-page-refreshing.tid
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
created: 20190111150102847
|
||||||
|
modified: 20190111150102847
|
||||||
|
tags: HookMechanism
|
||||||
|
title: Hook: th-page-refreshing
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
This hook notifies plugins that a page refresh is just about to occur. It is typically used to apply pre-rendering effects.
|
||||||
|
|
||||||
|
Hook function parameters:
|
||||||
|
|
||||||
|
* (none)
|
||||||
|
|
||||||
|
Return value:
|
||||||
|
|
||||||
|
* (none)
|
2
editions/dynaviewdemo/tiddlers/AnimationDuration.tid
Normal file
2
editions/dynaviewdemo/tiddlers/AnimationDuration.tid
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
title: $:/config/AnimationDuration
|
||||||
|
text: 0
|
@ -1,2 +1,2 @@
|
|||||||
title: $:/config/Performance/Instrumentation
|
title: $:/config/Performance/Instrumentation
|
||||||
text: yes
|
text: no
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
title: $:/config/DynaView/PreserveScrollPosition
|
||||||
|
text: yes
|
@ -17,11 +17,9 @@ caption: {{$:/language/SideBar/Open/Caption}}
|
|||||||
<div>
|
<div>
|
||||||
<$button message="tm-close-tiddler" tooltip={{$:/language/Buttons/Close/Hint}} aria-label={{$:/language/Buttons/Close/Caption}} class="tc-btn-invisible tc-btn-mini">×</$button> <$link to={{!!title}}><$view field="title"/></$link>
|
<$button message="tm-close-tiddler" tooltip={{$:/language/Buttons/Close/Hint}} aria-label={{$:/language/Buttons/Close/Caption}} class="tc-btn-invisible tc-btn-mini">×</$button> <$link to={{!!title}}><$view field="title"/></$link>
|
||||||
|
|
||||||
<$set name="state" value={{{ [[$:/state/viewtemplate/visibility/]addsuffix<currentTiddler>] }}}>
|
<$reveal type="match" stateTitle={{{ [[$:/state/viewtemplate/visibility/]addsuffix<currentTiddler>] }}} text="true">
|
||||||
<$set name="visibility" tiddler=<<state>>>
|
<span style="display: inline-block; background: red; color: white; padding: 2px; border-radius: 2px;font-size: 0.5em;line-height: 1;text-shadow: none;font-weight: bold;vertical-align: middle;">LOADED</span>
|
||||||
- <$text text=<<visibility>>/>
|
</$reveal>
|
||||||
</$set>
|
|
||||||
</$set>
|
|
||||||
</div>
|
</div>
|
||||||
</$droppable>
|
</$droppable>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,6 +13,12 @@ The components of this plugin include:
|
|||||||
|
|
||||||
! Scroll Features
|
! Scroll Features
|
||||||
|
|
||||||
|
!! Scroll Position Preservation
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
!! Set tiddler field when visible
|
!! 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.
|
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.
|
||||||
|
@ -24,11 +24,21 @@ var isWaitingForAnimationFrame = 0, // Bitmask:
|
|||||||
ANIM_FRAME_CAUSED_BY_RESIZE = 4; // Animation frame was requested because of window resize
|
ANIM_FRAME_CAUSED_BY_RESIZE = 4; // Animation frame was requested because of window resize
|
||||||
|
|
||||||
exports.startup = function() {
|
exports.startup = function() {
|
||||||
|
var topmost = null, lastScrollY;
|
||||||
window.addEventListener("load",onLoad,false);
|
window.addEventListener("load",onLoad,false);
|
||||||
window.addEventListener("scroll",onScroll,false);
|
window.addEventListener("scroll",onScroll,false);
|
||||||
window.addEventListener("resize",onResize,false);
|
window.addEventListener("resize",onResize,false);
|
||||||
|
$tw.hooks.addHook("th-page-refreshing",function() {
|
||||||
|
if(shouldPreserveScrollPosition()) {
|
||||||
|
topmost = findTopmostTiddler();
|
||||||
|
}
|
||||||
|
lastScrollY = window.scrollY;
|
||||||
|
});
|
||||||
$tw.hooks.addHook("th-page-refreshed",function() {
|
$tw.hooks.addHook("th-page-refreshed",function() {
|
||||||
checkTopmost();
|
if(lastScrollY === window.scrollY) { // Don't do scroll anchoring if the scroll position got changed
|
||||||
|
scrollToTiddler(topmost);
|
||||||
|
}
|
||||||
|
updateAddressBar();
|
||||||
checkVisibility();
|
checkVisibility();
|
||||||
saveViewportDimensions();
|
saveViewportDimensions();
|
||||||
});
|
});
|
||||||
@ -60,7 +70,7 @@ function worker() {
|
|||||||
saveViewportDimensions();
|
saveViewportDimensions();
|
||||||
}
|
}
|
||||||
setZoomClasses();
|
setZoomClasses();
|
||||||
checkTopmost();
|
updateAddressBar();
|
||||||
checkVisibility();
|
checkVisibility();
|
||||||
isWaitingForAnimationFrame = 0;
|
isWaitingForAnimationFrame = 0;
|
||||||
}
|
}
|
||||||
@ -134,22 +144,11 @@ function checkVisibility() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkTopmost() {
|
function updateAddressBar() {
|
||||||
if($tw.wiki.getTiddlerText("$:/config/DynaView/UpdateAddressBar") === "yes") {
|
if($tw.wiki.getTiddlerText("$:/config/DynaView/UpdateAddressBar") === "yes") {
|
||||||
var elements = document.querySelectorAll(".tc-tiddler-frame[data-tiddler-title]"),
|
var top = findTopmostTiddler();
|
||||||
topmostElement = null,
|
if(top.element) {
|
||||||
topmostElementTop = 1 * 1000 * 1000;
|
var hash = "#" + encodeURIComponent(top.title) + ":" + encodeURIComponent("[list[$:/StoryList]]");
|
||||||
$tw.utils.each(elements,function(element) {
|
|
||||||
// Check if the element is visible
|
|
||||||
var elementRect = element.getBoundingClientRect();
|
|
||||||
if((elementRect.top < topmostElementTop) && (elementRect.bottom > 0)) {
|
|
||||||
topmostElement = element;
|
|
||||||
topmostElementTop = elementRect.top;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if(topmostElement) {
|
|
||||||
var title = topmostElement.getAttribute("data-tiddler-title"),
|
|
||||||
hash = "#" + encodeURIComponent(title) + ":" + encodeURIComponent("[list[$:/StoryList]]");
|
|
||||||
if(title && $tw.locationHash !== hash) {
|
if(title && $tw.locationHash !== hash) {
|
||||||
$tw.locationHash = hash;
|
$tw.locationHash = hash;
|
||||||
window.location.hash = hash;
|
window.location.hash = hash;
|
||||||
@ -158,6 +157,51 @@ function checkTopmost() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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) {
|
||||||
|
var elements = document.querySelectorAll(".tc-tiddler-frame[data-tiddler-title]"),
|
||||||
|
topmostTiddlerElement = null;
|
||||||
|
$tw.utils.each(elements,function(element) {
|
||||||
|
if(element.getAttribute("data-tiddler-title") === tiddlerDetails.title) {
|
||||||
|
topmostTiddlerElement = element;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(topmostTiddlerElement) {
|
||||||
|
var rect = topmostTiddlerElement.getBoundingClientRect(),
|
||||||
|
scrollY = Math.round(window.scrollY + rect.top + tiddlerDetails.offset);
|
||||||
|
if(scrollY !== window.scrollY) {
|
||||||
|
window.scrollTo(window.scrollX,scrollY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldPreserveScrollPosition() {
|
||||||
|
return $tw.wiki.getTiddlerText("$:/config/DynaView/PreserveScrollPosition") === "yes";
|
||||||
|
}
|
||||||
|
|
||||||
|
function findTopmostTiddler() {
|
||||||
|
var elements = document.querySelectorAll(".tc-tiddler-frame[data-tiddler-title]"),
|
||||||
|
topmostElement = null,
|
||||||
|
topmostElementTop = 1 * 1000 * 1000;
|
||||||
|
$tw.utils.each(elements,function(element) {
|
||||||
|
// Check if the element is visible
|
||||||
|
var elementRect = element.getBoundingClientRect();
|
||||||
|
if((elementRect.top < topmostElementTop) && (elementRect.bottom > 0)) {
|
||||||
|
topmostElement = element;
|
||||||
|
topmostElementTop = elementRect.top;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
element: topmostElement,
|
||||||
|
offset: -topmostElementTop,
|
||||||
|
title: topmostElement.getAttribute("data-tiddler-title")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var previousViewportWidth, previousViewportHeight;
|
var previousViewportWidth, previousViewportHeight;
|
||||||
|
|
||||||
function saveViewportDimensions() {
|
function saveViewportDimensions() {
|
||||||
|
@ -1,8 +1,19 @@
|
|||||||
title: $:/plugins/tiddlywiki/dynaview/styles
|
title: $:/plugins/tiddlywiki/dynaview/styles
|
||||||
tags: $:/tags/Stylesheet
|
tags: $:/tags/Stylesheet
|
||||||
|
|
||||||
|
\define if-tiddler-is(title,value,text)
|
||||||
|
<$reveal stateTitle=<<__title__>> text=<<__value__>> type="match">
|
||||||
|
<$text text=<<__text__>>/>
|
||||||
|
</$reveal>
|
||||||
|
\end
|
||||||
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline
|
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline
|
||||||
|
|
||||||
|
<<if-tiddler-is title:"$:/config/DynaView/PreserveScrollPosition" value:"yes" text:"""
|
||||||
|
body {
|
||||||
|
overflow-anchor: none; /* Turn off browser scroll anchoring */
|
||||||
|
}
|
||||||
|
""">>
|
||||||
|
|
||||||
body.tc-dynaview .tc-dynaview-zoom-visible-1-and-above,
|
body.tc-dynaview .tc-dynaview-zoom-visible-1-and-above,
|
||||||
body.tc-dynaview .tc-dynaview-zoom-visible-1a-and-above,
|
body.tc-dynaview .tc-dynaview-zoom-visible-1a-and-above,
|
||||||
body.tc-dynaview .tc-dynaview-zoom-visible-1b-and-above,
|
body.tc-dynaview .tc-dynaview-zoom-visible-1b-and-above,
|
||||||
|
Loading…
Reference in New Issue
Block a user