Compare commits
30 Commits
2339518bd0
...
02e9c3e07a
Author | SHA1 | Date |
---|---|---|
lin onetwo | 02e9c3e07a | |
Matt Lauber | a081e58273 | |
Joshua Fontany | 5f74f4c2fa | |
Joshua Fontany | 9167b190d2 | |
linonetwo | 13d0c5cbd5 | |
linonetwo | 13f6bd84e9 | |
linonetwo | 48d2eff33c | |
linonetwo | 507d004a57 | |
linonetwo | ebf84b59e8 | |
linonetwo | 436343ce1b | |
linonetwo | dfa060024e | |
linonetwo | 0d18b25b26 | |
linonetwo | fef444cb1c | |
linonetwo | cff0240ac8 | |
linonetwo | a5c2f8558e | |
linonetwo | 07130c2ad0 | |
linonetwo | 3bcd822c97 | |
linonetwo | c0b6b7988a | |
linonetwo | 7200f73cdc | |
linonetwo | db83401a69 | |
linonetwo | e6445b79c5 | |
linonetwo | 0863916f9b | |
linonetwo | d8bdd09eb0 | |
linonetwo | 6b6124369c | |
linonetwo | 3d8ade3ebe | |
linonetwo | b956e72536 | |
linonetwo | d5e9d2a71b | |
linonetwo | 18236b547f | |
linonetwo | 4c407c28e4 | |
linonetwo | 5b6f5b2704 |
|
@ -43,7 +43,9 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
|
|||
directory: path.resolve(self.commander.outputPath),
|
||||
pathFilters: [filenameFilter],
|
||||
wiki: wiki,
|
||||
fileInfo: {}
|
||||
fileInfo: {
|
||||
overwrite: true
|
||||
}
|
||||
});
|
||||
if(self.commander.verbose) {
|
||||
console.log("Saving \"" + title + "\" to \"" + fileInfo.filepath + "\"");
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*\
|
||||
title: $:/core/modules/parsers/wikiparser/rules/anchor.js
|
||||
type: application/javascript
|
||||
module-type: wikirule
|
||||
|
||||
Use hash as a tag for paragraph, we call it anchor.
|
||||
|
||||
1. Hash won't change, it can be written by hand or be generated, and it is a ` \^\S+$` string after line: `text ^cb9d485` or `text ^1`, so it can be human readable (while without space), here are the parse rule for this.
|
||||
2. When creating widgets for rendering, omit this hash, so it's invisible in view mode. But this widget will create an anchor to jump to.
|
||||
|
||||
\*/
|
||||
exports.name = "anchor";
|
||||
exports.types = {inline: true};
|
||||
|
||||
/*
|
||||
Instantiate parse rule
|
||||
*/
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match the anchor.
|
||||
// 1. located on the end of the line, with a space before it, means it's the id of the current block.
|
||||
// 2. located at start of the line, no space, means it's the id of the previous block. Because some block can't have id suffix, otherwise id break the block mode parser like codeblock.
|
||||
this.matchRegExp = /[ ]\^(\S+)$|^\^(\S+)$/mg;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse the most recent match
|
||||
*/
|
||||
exports.parse = function() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// will be one of following case, another will be undefined
|
||||
var anchorId = this.match[1];
|
||||
var anchorBeforeId = this.match[2];
|
||||
// Parse tree nodes to return
|
||||
return [{
|
||||
type: "anchor",
|
||||
attributes: {
|
||||
id: {type: "string", value: anchorId || anchorBeforeId},
|
||||
// `yes` means the block that this anchor pointing to, is before this node, both anchor and the block, is in a same parent node's children list.
|
||||
// empty means the block is this node's direct parent node.
|
||||
previousSibling: {type: "string", value: Boolean(anchorBeforeId) ? "yes" : ""},
|
||||
},
|
||||
children: []
|
||||
}];
|
||||
};
|
|
@ -23,8 +23,8 @@ exports.types = {inline: true};
|
|||
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /\[\[(.*?)(?:\|(.*?))?\]\]/mg;
|
||||
// Regexp to match `[[Alias|Title^blockId]]`, the `Alias|` and `^blockId` are optional.
|
||||
this.matchRegExp = /\[\[(.*?)(?:\|(.*?)?)?(?:\^([^|\s^]+)?)?\]\]/mg;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
|
@ -32,8 +32,13 @@ exports.parse = function() {
|
|||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Process the link
|
||||
var text = this.match[1],
|
||||
link = this.match[2] || text;
|
||||
link = this.match[2] || text,
|
||||
anchor = this.match[3] || "";
|
||||
if($tw.utils.isLinkExternal(link)) {
|
||||
// add back the part after `^` to the ext link, if it happen to has one.
|
||||
if(anchor) {
|
||||
link = link + "^" + anchor;
|
||||
}
|
||||
return [{
|
||||
type: "element",
|
||||
tag: "a",
|
||||
|
@ -51,7 +56,8 @@ exports.parse = function() {
|
|||
return [{
|
||||
type: "link",
|
||||
attributes: {
|
||||
to: {type: "string", value: link}
|
||||
to: {type: "string", value: link},
|
||||
toAnchor: {type: "string", value: anchor},
|
||||
},
|
||||
children: [{
|
||||
type: "text", text: text
|
||||
|
|
|
@ -140,6 +140,11 @@ function sendResponse(request,response,statusCode,headers,data,encoding) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// RFC 7231, 6.1. Overview of Status Codes:
|
||||
// Browser clients may cache 200, 203, 204, 206, 300, 301,
|
||||
// 404, 405, 410, 414, and 501 unless given explicit cache controls
|
||||
headers["Cache-Control"] = headers["Cache-Control"] || "no-store";
|
||||
}
|
||||
/*
|
||||
If the gzip=yes is set, check if the user agent permits compression. If so,
|
||||
|
|
|
@ -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];
|
||||
// Add a new record to the top of the history stack
|
||||
var historyList = this.wiki.getTiddlerData(this.historyTitle,[]);
|
||||
$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]});
|
||||
};
|
||||
|
|
|
@ -26,13 +26,24 @@ ClassicStoryView.prototype.navigateTo = function(historyInfo) {
|
|||
}
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// If anchor is provided, find the element the anchor pointing to
|
||||
var foundAnchor = false;
|
||||
if(listItemWidget && historyInfo.anchor) {
|
||||
var anchorWidget = $tw.utils.findChildNodeInTree(listItemWidget, function(widget) {
|
||||
return widget.anchorId === historyInfo.anchor;
|
||||
});
|
||||
if(anchorWidget) {
|
||||
targetElement = anchorWidget.findAnchorTargetDomNode()
|
||||
foundAnchor = true;
|
||||
}
|
||||
}
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
if(duration) {
|
||||
// Scroll the node into view
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement});
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement, highlight: foundAnchor});
|
||||
} else {
|
||||
targetElement.scrollIntoView();
|
||||
}
|
||||
|
|
|
@ -23,12 +23,23 @@ PopStoryView.prototype.navigateTo = function(historyInfo) {
|
|||
}
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// If anchor is provided, find the element the anchor pointing to
|
||||
var foundAnchor = false;
|
||||
if(listItemWidget && historyInfo.anchor) {
|
||||
var anchorWidget = $tw.utils.findChildNodeInTree(listItemWidget, function(widget) {
|
||||
return widget.anchorId === historyInfo.anchor;
|
||||
});
|
||||
if(anchorWidget) {
|
||||
targetElement = anchorWidget.findAnchorTargetDomNode()
|
||||
foundAnchor = true;
|
||||
}
|
||||
}
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||
return;
|
||||
}
|
||||
// Scroll the node into view
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement});
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement, highlight: foundAnchor});
|
||||
};
|
||||
|
||||
PopStoryView.prototype.insert = function(widget) {
|
||||
|
|
|
@ -51,6 +51,16 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
|
|||
}
|
||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||
targetElement = listItemWidget.findFirstDomNode();
|
||||
// If anchor is provided, find the element the anchor pointing to
|
||||
var anchorElement = null;
|
||||
if(listItemWidget && historyInfo.anchor) {
|
||||
var anchorWidget = $tw.utils.findChildNodeInTree(listItemWidget, function(widget) {
|
||||
return widget.anchorId === historyInfo.anchor;
|
||||
});
|
||||
if(anchorWidget) {
|
||||
anchorElement = anchorWidget.findAnchorTargetDomNode()
|
||||
}
|
||||
}
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
if(!targetElement) {
|
||||
return;
|
||||
|
@ -119,7 +129,10 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
|
|||
},duration);
|
||||
}
|
||||
// Scroll the target into view
|
||||
// $tw.pageScroller.scrollIntoView(targetElement);
|
||||
if(anchorElement) {
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: anchorElement, highlight: true});
|
||||
}
|
||||
// $tw.pageScroller.scrollIntoView(targetElement);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -283,7 +283,7 @@ exports.httpRequest = function(options) {
|
|||
// Set up the state change handler
|
||||
request.onreadystatechange = function() {
|
||||
if(this.readyState === 4) {
|
||||
if(this.status === 200 || this.status === 201 || this.status === 204) {
|
||||
if(this.status >= 200 && this.status < 300) {
|
||||
// Success!
|
||||
options.callback(null,this[returnProp],this);
|
||||
return;
|
||||
|
|
|
@ -49,7 +49,9 @@ Handle an event
|
|||
*/
|
||||
PageScroller.prototype.handleEvent = function(event) {
|
||||
if(event.type === "tm-scroll") {
|
||||
var options = {};
|
||||
var options = {
|
||||
highlight: event.highlight,
|
||||
};
|
||||
if($tw.utils.hop(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
|
||||
|
||||
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) {
|
||||
var self = this,
|
||||
duration = $tw.utils.hop(options,"animationDuration") ? parseInt(options.animationDuration) : $tw.utils.getAnimationDuration(),
|
||||
highlight = options.highlight || false,
|
||||
srcWindow = element ? element.ownerDocument.defaultView : window;
|
||||
// Now get ready to scroll the body
|
||||
this.cancelScroll(srcWindow);
|
||||
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
|
||||
var toolbar = srcWindow.document.querySelector(".tc-adjust-top-of-scroll"),
|
||||
offset = 0;
|
||||
|
@ -121,6 +130,12 @@ PageScroller.prototype.scrollIntoView = function(element,callback,options) {
|
|||
srcWindow.scrollTo(scrollPosition.x + (endX - scrollPosition.x) * t,scrollPosition.y + (endY - scrollPosition.y) * t);
|
||||
if(t < 1) {
|
||||
self.idRequestFrame = self.requestAnimationFrame.call(srcWindow,drawFrame);
|
||||
} else {
|
||||
// the animation is end.
|
||||
if(highlight) {
|
||||
element.focus({ focusVisible: true });
|
||||
$tw.utils.addClass(element,"tc-focus-highlight");
|
||||
}
|
||||
}
|
||||
};
|
||||
drawFrame();
|
||||
|
|
|
@ -316,11 +316,13 @@ Options include:
|
|||
pathFilters: optional array of filters to be used to generate the base path
|
||||
wiki: optional wiki for evaluating the pathFilters
|
||||
fileInfo: an existing fileInfo object to check against
|
||||
fileInfo.overwrite: if true, turns off filename clash numbers (defaults to false)
|
||||
*/
|
||||
exports.generateTiddlerFilepath = function(title,options) {
|
||||
var directory = options.directory || "",
|
||||
extension = options.extension || "",
|
||||
originalpath = (options.fileInfo && options.fileInfo.originalpath) ? options.fileInfo.originalpath : "",
|
||||
overwrite = options.fileInfo && options.fileInfo.overwrite || false,
|
||||
filepath;
|
||||
// Check if any of the pathFilters applies
|
||||
if(options.pathFilters && options.wiki) {
|
||||
|
@ -381,19 +383,20 @@ exports.generateTiddlerFilepath = function(title,options) {
|
|||
filepath += char.charCodeAt(0).toString();
|
||||
});
|
||||
}
|
||||
// Add a uniquifier if the file already exists
|
||||
var fullPath, oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
|
||||
// Add a uniquifier if the file already exists (default)
|
||||
var fullPath = path.resolve(directory, filepath + extension);
|
||||
if (!overwrite) {
|
||||
var oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
|
||||
count = 0;
|
||||
do {
|
||||
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
|
||||
if(oldPath && oldPath == fullPath) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
} while(fs.existsSync(fullPath));
|
||||
do {
|
||||
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
|
||||
if(oldPath && oldPath == fullPath) break;
|
||||
count++;
|
||||
} while(fs.existsSync(fullPath));
|
||||
}
|
||||
// If the last write failed with an error, or if path does not start with:
|
||||
// the resolved options.directory, the resolved wikiPath directory, the wikiTiddlersPath directory,
|
||||
// or the 'originalpath' directory, then $tw.utils.encodeURIComponentExtended() and resolve to tiddler directory.
|
||||
// or the 'originalpath' directory, then $tw.utils.encodeURIComponentExtended() and resolve to options.directory.
|
||||
var writePath = $tw.hooks.invokeHook("th-make-tiddler-path",fullPath,fullPath),
|
||||
encode = (options.fileInfo || {writeError: false}).writeError == true;
|
||||
if(!encode) {
|
||||
|
|
|
@ -103,6 +103,21 @@ exports.findParseTreeNode = function(nodeArray,search) {
|
|||
return undefined;
|
||||
};
|
||||
|
||||
exports.findChildNodeInTree = function(root,searchFn) {
|
||||
if(searchFn(root)) {
|
||||
return root;
|
||||
}
|
||||
if(root.children && root.children.length > 0) {
|
||||
for(var i=0; i<root.children.length; i++) {
|
||||
var result = exports.findChildNodeInTree(root.children[i], searchFn);
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/*
|
||||
Helper to get the text of a parse tree node or array of nodes
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*\
|
||||
title: $:/core/modules/widgets/anchor.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
An invisible element with anchor id metadata.
|
||||
\*/
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
var AnchorWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
// only this widget knows target info (if the block is before this node or not), so we need to hook the focus event, and process it here, instead of in the root widget.
|
||||
};
|
||||
AnchorWidget.prototype = new Widget();
|
||||
|
||||
AnchorWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Save the parent dom node
|
||||
this.parentDomNode = parent;
|
||||
// Compute our attributes
|
||||
this.computeAttributes();
|
||||
// Execute our logic
|
||||
this.execute();
|
||||
// Create an invisible DOM element with data that can be accessed from JS or CSS
|
||||
this.idNode = this.document.createElement("span");
|
||||
this.idNode.setAttribute("data-anchor-id",this.anchorId);
|
||||
this.idNode.setAttribute("data-anchor-title",this.tiddlerTitle);
|
||||
// if the actual block is before this node, we need to add a flag to the node
|
||||
if(this.previousSibling) {
|
||||
this.idNode.setAttribute("data-anchor-previous-sibling","true");
|
||||
}
|
||||
this.idNode.className = "tc-anchor";
|
||||
parent.insertBefore(this.idNode,nextSibling);
|
||||
this.domNodes.push(this.idNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
AnchorWidget.prototype.execute = function() {
|
||||
// Get the id from the parse tree node or manually assigned attributes
|
||||
this.anchorId = this.getAttribute("id");
|
||||
this.tiddlerTitle = this.getVariable("currentTiddler");
|
||||
this.previousSibling = this.getAttribute("previousSibling") === "yes";
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Find the DOM node pointed by this anchor
|
||||
*/
|
||||
Widget.prototype.findAnchorTargetDomNode = function() {
|
||||
if(!this.idNode) {
|
||||
return null;
|
||||
}
|
||||
// the actual block is always at the parent level
|
||||
targetElement = this.idNode.parentNode;
|
||||
// need to check if the block is before this node
|
||||
if(this.previousSibling) {
|
||||
targetElement = targetElement.previousSibling;
|
||||
}
|
||||
return targetElement;
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
AnchorWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(($tw.utils.count(changedAttributes) > 0)) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
}
|
||||
};
|
||||
|
||||
exports.anchor = AnchorWidget;
|
|
@ -160,6 +160,7 @@ LinkWidget.prototype.handleClickEvent = function(event) {
|
|||
this.dispatchEvent({
|
||||
type: "tm-navigate",
|
||||
navigateTo: this.to,
|
||||
toAnchor: this.toAnchor,
|
||||
navigateFromTitle: this.getVariable("storyTiddler"),
|
||||
navigateFromNode: this,
|
||||
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||
|
@ -190,6 +191,7 @@ Compute the internal state of the widget
|
|||
LinkWidget.prototype.execute = function() {
|
||||
// Pick up our attributes
|
||||
this.to = this.getAttribute("to",this.getVariable("currentTiddler"));
|
||||
this.toAnchor = this.getAttribute("toAnchor");
|
||||
this.tooltip = this.getAttribute("tooltip");
|
||||
this["aria-label"] = this.getAttribute("aria-label");
|
||||
this.linkClasses = this.getAttribute("class");
|
||||
|
|
|
@ -138,9 +138,10 @@ NavigatorWidget.prototype.addToStory = function(title,fromTitle) {
|
|||
Add a new record to the top of the history stack
|
||||
title: a title string or an array of title strings
|
||||
fromPageRect: page coordinates of the origin of the navigation
|
||||
anchor:optional anchor id in this tiddler
|
||||
*/
|
||||
NavigatorWidget.prototype.addToHistory = function(title,fromPageRect) {
|
||||
this.story.addToHistory(title,fromPageRect,this.historyTitle);
|
||||
NavigatorWidget.prototype.addToHistory = function(title,fromPageRect,anchor) {
|
||||
this.story.addToHistory(title,fromPageRect,anchor);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -151,7 +152,7 @@ NavigatorWidget.prototype.handleNavigateEvent = function(event) {
|
|||
if(event.navigateTo) {
|
||||
this.addToStory(event.navigateTo,event.navigateFromTitle);
|
||||
if(!event.navigateSuppressNavigation) {
|
||||
this.addToHistory(event.navigateTo,event.navigateFromClientRect);
|
||||
this.addToHistory(event.navigateTo,event.navigateFromClientRect,event.toAnchor);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -4,7 +4,7 @@ tags: $:/tags/EditTemplate
|
|||
\whitespace trim
|
||||
<$edit-text field="draft.title" class="tc-titlebar tc-edit-texteditor" focus={{{ [{$:/config/AutoFocus}match[title]then[true]] ~[[false]] }}} tabindex={{$:/config/EditTabIndex}} cancelPopups="yes"/>
|
||||
|
||||
<$vars pattern="""[\|\[\]{}]""" bad-chars="""`| [ ] { }`""">
|
||||
<$vars pattern="""[\^\|\[\]{}]""" bad-chars="""`| ^ [ ] { }`""">
|
||||
|
||||
<$list filter="[all[current]regexp:draft.title<pattern>]" variable="listItem">
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
created: 20230922141042399
|
||||
modified: 20230922141423022
|
||||
tags:
|
||||
title: HistoryMechanism
|
||||
|
||||
The story view is created by [[$:/core/ui/PageTemplate/story]] core page template, which uses list widget to render tiddlers. In this way, page template will reflect to history's change.
|
||||
|
||||
List widget has a `history="$:/HistoryList"` parameter, that will be used in list widget's `handleHistoryChanges` method, and pass to the `this.storyview.navigateTo`, you can read [[storyview module]] for how storyview use the changed history.
|
|
@ -0,0 +1,34 @@
|
|||
caption: block id
|
||||
created: 20230916061829840
|
||||
modified: 20230922150245402
|
||||
tags: Widgets
|
||||
title: AnchorWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
! Introduction
|
||||
|
||||
The block id widget make an anchor that can be focused and jump to.
|
||||
|
||||
! Content and Attributes
|
||||
|
||||
The content of the `<$anchor>` widget is ignored.
|
||||
|
||||
|!Attribute |!Description |
|
||||
|id |The unique id for the block |
|
||||
|previousSibling |`yes` means the block is before this node, in parent node's children list, else it means the block is this node's direct parent node. |
|
||||
|
||||
See [[Block Level Links in WikiText^🤗→AddingIDforblock]] for WikiText syntax of block ID.
|
||||
|
||||
! Example
|
||||
|
||||
<<wikitext-example-without-html """The block id widget is invisible, and is usually located at the end of the line. ID is here:<$anchor id="BlockLevelLinksID1"/>
|
||||
|
||||
[[Link to BlockLevelLinksID1|AnchorWidget^BlockLevelLinksID1]]
|
||||
""">>
|
||||
|
||||
<<wikitext-example """You can refer to the block that is a line before the block id widget. Make sure block id widget itself is in a block (paragraph).
|
||||
|
||||
ID is here:<$anchor id="BlockLevelLinksID2" previousSibling="yes"/>
|
||||
|
||||
[[Link to BlockLevelLinksID2|AnchorWidget^BlockLevelLinksID2]]
|
||||
""">>
|
|
@ -16,6 +16,7 @@ The content of the link widget is rendered within the `<a>` tag representing the
|
|||
|
||||
|!Attribute |!Description |
|
||||
|to |The title of the target tiddler for the link (defaults to the [[current tiddler|Current Tiddler]]) |
|
||||
|toAnchor |<<.from-version "5.3.2">> Optional id of the anchor for [[Block Level Links in WikiText]] |
|
||||
|aria-label |Optional accessibility label |
|
||||
|tooltip |Optional tooltip WikiText |
|
||||
|tabindex |Optional numeric [[tabindex|https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/tabIndex]] |
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
caption: Block Level Links
|
||||
created: 20230916061138153
|
||||
modified: 20230922150740619
|
||||
tags: WikiText
|
||||
title: Block Level Links in WikiText
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<wikitext-example-without-html src:"! Adding ID for block ^🤗→AddingIDforblock">>
|
||||
|
||||
The basic syntax for block id is:
|
||||
|
||||
<<wikitext-example src:"There is a block id that is invisible, but you can find it using developer tool's inspect element feature. ^BlockLevelLinksID1">>
|
||||
|
||||
# Don't forget the space between the end of the line and the `^`.
|
||||
# And there is no space between `^` and the id.
|
||||
# ID can contain any char other than `^` and space ` `.
|
||||
|
||||
And this block id widget will be rendered as an invisible element:
|
||||
|
||||
```html
|
||||
<span class="tc-block-id" data-block-id="BlockLevelLinksID1" data-block-title="Block Level Links in WikiText"></span>
|
||||
```
|
||||
|
||||
!! Adding id to previous block
|
||||
|
||||
Some block, for example, code block, can't be suffixed by `^id`, but we can add the id in the next line, with no space prefix to it.
|
||||
|
||||
<<wikitext-example src:"```css
|
||||
.main {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
^BlockLevelLinksID2
|
||||
|
||||
">>
|
||||
|
||||
! Link to the block ID ^091607
|
||||
|
||||
Adding `^blockID` after the title in the link, will make this link highlight the block with that ID.
|
||||
|
||||
<<wikitext-example-without-html src:"[[Link to BlockLevelLinksID1|Block Level Links in WikiText^BlockLevelLinksID1]]">>
|
||||
|
||||
<<wikitext-example-without-html src:"[[Link to BlockLevelLinksID2|Block Level Links in WikiText^BlockLevelLinksID2]]">>
|
||||
|
||||
<<wikitext-example-without-html src:"[[Link to Title|Block Level Links in WikiText^🤗→AddingIDforblock]]">>
|
||||
|
||||
<<wikitext-example-without-html src:"[[Link to Non-existing anchor|Block Level Links in WikiText^😂❎]]">>
|
|
@ -1,6 +1,6 @@
|
|||
caption: Linking
|
||||
created: 20131205155230596
|
||||
modified: 20211230145939554
|
||||
modified: 20230917121659927
|
||||
tags: WikiText
|
||||
title: Linking in WikiText
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -123,3 +123,9 @@ See also another example of [[constructing dynamic links|Concatenating text and
|
|||
In TiddlyWiki anchor links can help us link to target points and distinct sections within rendered tiddlers. They can help the reader navigate longer tiddler content.
|
||||
|
||||
See [[Anchor Links using HTML]] for more information.
|
||||
|
||||
! Linking within tiddlers - Link to block
|
||||
|
||||
You can link to a specific block within a tiddler using `^blockId` syntax. You will also get block level backlinks with this technique. Some examples are in [[BlockIdWidget^exampleid1]].
|
||||
|
||||
See [[Block Level Links in WikiText^091607]] for more information.
|
||||
|
|
|
@ -2446,6 +2446,21 @@ html body.tc-body.tc-single-tiddler-window {
|
|||
color: <<colour alert-highlight>>;
|
||||
}
|
||||
|
||||
@keyframes fade-highlight {
|
||||
0% {
|
||||
background-color: <<colour highlight-background>>;
|
||||
border-color: <<colour highlight-background>>;
|
||||
}
|
||||
100% {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.tc-focus-highlight {
|
||||
animation: fade-highlight 2s forwards;
|
||||
}
|
||||
|
||||
@media (min-width: <<sidebarbreakpoint>>) {
|
||||
|
||||
.tc-static-alert {
|
||||
|
|
Loading…
Reference in New Issue