1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2025-01-10 17:30:26 +00:00

refactor: use history mechanism for block level navigation

This commit is contained in:
linonetwo 2023-09-22 23:14:22 +08:00
parent dfa060024e
commit 436343ce1b
5 changed files with 42 additions and 10 deletions

View File

@ -90,12 +90,12 @@ Story.prototype.saveStoryList = function(storyList) {
)); ));
}; };
Story.prototype.addToHistory = function(navigateTo,navigateFromClientRect) { Story.prototype.addToHistory = function(navigateTo,fromPageRect,anchor) {
var titles = $tw.utils.isArray(navigateTo) ? navigateTo : [navigateTo]; var titles = $tw.utils.isArray(navigateTo) ? navigateTo : [navigateTo];
// Add a new record to the top of the history stack // Add a new record to the top of the history stack
var historyList = this.wiki.getTiddlerData(this.historyTitle,[]); var historyList = this.wiki.getTiddlerData(this.historyTitle,[]);
$tw.utils.each(titles,function(title) { $tw.utils.each(titles,function(title) {
historyList.push({title: title, fromPageRect: navigateFromClientRect}); historyList.push({title: title, fromPageRect: fromPageRect, anchor: anchor});
}); });
this.wiki.setTiddlerData(this.historyTitle,historyList,{"current-tiddler": titles[titles.length-1]}); this.wiki.setTiddlerData(this.historyTitle,historyList,{"current-tiddler": titles[titles.length-1]});
}; };

View File

@ -26,13 +26,26 @@ ClassicStoryView.prototype.navigateTo = function(historyInfo) {
} }
var listItemWidget = this.listWidget.children[listElementIndex], var listItemWidget = this.listWidget.children[listElementIndex],
targetElement = listItemWidget.findFirstDomNode(); targetElement = listItemWidget.findFirstDomNode();
// If anchor is provided, find the element the anchor pointing to
var foundAnchor = false;
if(targetElement && historyInfo.anchor) {
var anchorElement = targetElement.querySelector("[data-anchor-id='" + historyInfo.anchor + "']");
if(anchorElement) {
targetElement = anchorElement.parentNode;
var isBefore = anchorElement.dataset.anchorPreviousSibling === "true";
if(isBefore) {
targetElement = targetElement.previousSibling;
}
foundAnchor = true;
}
}
// Abandon if the list entry isn't a DOM element (it might be a text node) // Abandon if the list entry isn't a DOM element (it might be a text node)
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) { if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
return; return;
} }
if(duration) { if(duration) {
// Scroll the node into view // Scroll the node into view
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement}); this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement, highlight: foundAnchor});
} else { } else {
targetElement.scrollIntoView(); targetElement.scrollIntoView();
} }

View File

@ -49,7 +49,9 @@ Handle an event
*/ */
PageScroller.prototype.handleEvent = function(event) { PageScroller.prototype.handleEvent = function(event) {
if(event.type === "tm-scroll") { if(event.type === "tm-scroll") {
var options = {}; var options = {
highlight: event.highlight,
};
if($tw.utils.hop(event.paramObject,"animationDuration")) { if($tw.utils.hop(event.paramObject,"animationDuration")) {
options.animationDuration = event.paramObject.animationDuration; options.animationDuration = event.paramObject.animationDuration;
} }
@ -65,14 +67,21 @@ PageScroller.prototype.handleEvent = function(event) {
/* /*
Handle a scroll event hitting the page document Handle a scroll event hitting the page document
options:
- animationDuration: total time of scroll animation
- highlight: highlight the element after scrolling, to make it evident. Usually to focus an anchor in the middle of the tiddler.
*/ */
PageScroller.prototype.scrollIntoView = function(element,callback,options) { PageScroller.prototype.scrollIntoView = function(element,callback,options) {
var self = this, var self = this,
duration = $tw.utils.hop(options,"animationDuration") ? parseInt(options.animationDuration) : $tw.utils.getAnimationDuration(), duration = $tw.utils.hop(options,"animationDuration") ? parseInt(options.animationDuration) : $tw.utils.getAnimationDuration(),
highlight = options.highlight || false,
srcWindow = element ? element.ownerDocument.defaultView : window; srcWindow = element ? element.ownerDocument.defaultView : window;
// Now get ready to scroll the body // Now get ready to scroll the body
this.cancelScroll(srcWindow); this.cancelScroll(srcWindow);
this.startTime = Date.now(); this.startTime = Date.now();
// toggle class to allow trigger the highlight animation
$tw.utils.removeClass(element,"tc-focus-highlight");
// Get the height of any position:fixed toolbars // Get the height of any position:fixed toolbars
var toolbar = srcWindow.document.querySelector(".tc-adjust-top-of-scroll"), var toolbar = srcWindow.document.querySelector(".tc-adjust-top-of-scroll"),
offset = 0; offset = 0;
@ -121,6 +130,15 @@ PageScroller.prototype.scrollIntoView = function(element,callback,options) {
srcWindow.scrollTo(scrollPosition.x + (endX - scrollPosition.x) * t,scrollPosition.y + (endY - scrollPosition.y) * t); srcWindow.scrollTo(scrollPosition.x + (endX - scrollPosition.x) * t,scrollPosition.y + (endY - scrollPosition.y) * t);
if(t < 1) { if(t < 1) {
self.idRequestFrame = self.requestAnimationFrame.call(srcWindow,drawFrame); self.idRequestFrame = self.requestAnimationFrame.call(srcWindow,drawFrame);
} else {
// the animation is end.
if(highlight) {
element.focus({ focusVisible: true });
// Using setTimeout to ensure the removal takes effect before adding the class again.
setTimeout(function() {
$tw.utils.addClass(element,"tc-focus-highlight");
}, 50);
}
} }
}; };
drawFrame(); drawFrame();

View File

@ -23,8 +23,9 @@ AnchorWidget.prototype.render = function(parent,nextSibling) {
this.idNode = this.document.createElement("span"); this.idNode = this.document.createElement("span");
this.idNode.setAttribute("data-anchor-id",this.id); this.idNode.setAttribute("data-anchor-id",this.id);
this.idNode.setAttribute("data-anchor-title",this.tiddlerTitle); this.idNode.setAttribute("data-anchor-title",this.tiddlerTitle);
if(this.before) { // if the actual block is before this node, we need to add a flag to the node
this.idNode.setAttribute("data-before","true"); if(this.previousSibling) {
this.idNode.setAttribute("data-anchor-previous-sibling","true");
} }
this.idNode.className = "tc-anchor"; this.idNode.className = "tc-anchor";
parent.insertBefore(this.idNode,nextSibling); parent.insertBefore(this.idNode,nextSibling);

View File

@ -138,9 +138,10 @@ NavigatorWidget.prototype.addToStory = function(title,fromTitle) {
Add a new record to the top of the history stack Add a new record to the top of the history stack
title: a title string or an array of title strings title: a title string or an array of title strings
fromPageRect: page coordinates of the origin of the navigation fromPageRect: page coordinates of the origin of the navigation
anchor:optional anchor id in this tiddler
*/ */
NavigatorWidget.prototype.addToHistory = function(title,fromPageRect) { NavigatorWidget.prototype.addToHistory = function(title,fromPageRect,anchor) {
this.story.addToHistory(title,fromPageRect,this.historyTitle); this.story.addToHistory(title,fromPageRect,anchor);
}; };
/* /*
@ -150,9 +151,8 @@ NavigatorWidget.prototype.handleNavigateEvent = function(event) {
event = $tw.hooks.invokeHook("th-navigating",event); event = $tw.hooks.invokeHook("th-navigating",event);
if(event.navigateTo) { if(event.navigateTo) {
this.addToStory(event.navigateTo,event.navigateFromTitle); this.addToStory(event.navigateTo,event.navigateFromTitle);
event = $tw.hooks.invokeHook("th-navigating-add-history",event);
if(!event.navigateSuppressNavigation) { if(!event.navigateSuppressNavigation) {
this.addToHistory(event.navigateTo,event.navigateFromClientRect); this.addToHistory(event.navigateTo,event.navigateFromClientRect,event.toAnchor);
} }
} }
$tw.hooks.invokeHook("th-navigated",event); $tw.hooks.invokeHook("th-navigated",event);