mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-01-23 15:36:52 +00:00
refactor: rename anchor to block mark
This commit is contained in:
parent
98189a998d
commit
8c20319b3a
@ -1,15 +1,15 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/wikiparser/rules/anchor.js
|
||||
title: $:/core/modules/parsers/wikiparser/rules/blockmark.js
|
||||
type: application/javascript
|
||||
module-type: wikirule
|
||||
|
||||
Use hash as a tag for paragraph, we call it anchor.
|
||||
Use hash as a tag for paragraph, we call it block mark.
|
||||
|
||||
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.
|
||||
2. When creating widgets for rendering, omit this hash, so it's invisible in view mode. But this widget will create an mark to jump to.
|
||||
|
||||
\*/
|
||||
exports.name = "anchor";
|
||||
exports.name = "blockmark";
|
||||
exports.types = {inline: true};
|
||||
|
||||
/*
|
||||
@ -17,7 +17,7 @@ Instantiate parse rule
|
||||
*/
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match the anchor.
|
||||
// Regexp to match the block mark.
|
||||
// 1. inlineId: located on the end of the line, with a space before it, means it's the id of the current block.
|
||||
// 2. blockId: 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;
|
||||
@ -32,15 +32,15 @@ exports.parse = function() {
|
||||
// will be one of following case, another will be undefined
|
||||
var inlineId = this.match[1];
|
||||
var blockId = this.match[2];
|
||||
var id = inlineId || blockId || '';
|
||||
var anchorStart = this.parser.pos;
|
||||
var anchorEnd = anchorStart + id.length;
|
||||
var id = inlineId || blockId || "";
|
||||
var blockMarkStart = this.parser.pos;
|
||||
var blockMarkEnd = blockMarkStart + id.length;
|
||||
// Parse tree nodes to return
|
||||
return [{
|
||||
type: "anchor",
|
||||
type: "blockmark",
|
||||
attributes: {
|
||||
id: {type: "string", value: id, start: anchorStart, end: anchorEnd},
|
||||
// `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.
|
||||
id: {type: "string", value: id, start: blockMarkStart, end: blockMarkEnd},
|
||||
// `yes` means the block that this block mark pointing to, is before this node, both block mark and the block itself, 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(blockId) ? "yes" : ""},
|
||||
},
|
@ -34,7 +34,7 @@ exports.parse = function() {
|
||||
// Process the link
|
||||
var text = this.match[1],
|
||||
link = this.match[2] || text,
|
||||
anchor = this.match[3] || "",
|
||||
blockMark = this.match[3] || "",
|
||||
textEndPos = this.parser.source.indexOf("|", start);
|
||||
if (textEndPos < 0 || textEndPos > this.matchRegExp.lastIndex) {
|
||||
textEndPos = this.matchRegExp.lastIndex - 2;
|
||||
@ -42,9 +42,9 @@ exports.parse = function() {
|
||||
var linkStart = this.match[2] ? (start + this.match[1].length + 1) : start;
|
||||
var linkEnd = linkStart + link.length;
|
||||
if($tw.utils.isLinkExternal(link)) {
|
||||
// add back the part after `^` to the ext link, if it happen to has one. Here is is not an anchor, but a part of the external URL.
|
||||
if(anchor) {
|
||||
link = link + "^" + anchor;
|
||||
// add back the part after `^` to the ext link, if it happen to has one. Here is is not an block mark, but a part of the external URL.
|
||||
if(blockMark) {
|
||||
link = link + "^" + blockMark;
|
||||
}
|
||||
return [{
|
||||
type: "element",
|
||||
@ -60,13 +60,13 @@ exports.parse = function() {
|
||||
}]
|
||||
}];
|
||||
} else {
|
||||
var anchorStart = anchor ? (linkEnd + 1) : linkEnd;
|
||||
var anchorEnd = anchorStart + anchor.length;
|
||||
var blockMarkStart = blockMark ? (linkEnd + 1) : linkEnd;
|
||||
var blockMarkEnd = blockMarkStart + blockMark.length;
|
||||
return [{
|
||||
type: "link",
|
||||
attributes: {
|
||||
to: {type: "string", value: link, start: linkStart, end: linkEnd},
|
||||
toAnchor: {type: "string", value: anchor, start: anchorStart, end: anchorEnd},
|
||||
toBlockMark: {type: "string", value: blockMark, start: blockMarkStart, end: blockMarkEnd},
|
||||
},
|
||||
children: [{
|
||||
type: "text", text: text, start: start, end: textEndPos
|
||||
|
@ -90,12 +90,12 @@ Story.prototype.saveStoryList = function(storyList) {
|
||||
));
|
||||
};
|
||||
|
||||
Story.prototype.addToHistory = function(navigateTo,fromPageRect,anchor) {
|
||||
Story.prototype.addToHistory = function(navigateTo,fromPageRect,blockMark) {
|
||||
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: fromPageRect, anchor: anchor});
|
||||
historyList.push({title: title, fromPageRect: fromPageRect, blockMark: blockMark});
|
||||
});
|
||||
this.wiki.setTiddlerData(this.historyTitle,historyList,{"current-tiddler": titles[titles.length-1]});
|
||||
};
|
||||
|
@ -26,15 +26,15 @@ 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 block mark is provided, find the block element that this mark is pointing to
|
||||
var foundBlockMark = false;
|
||||
if(listItemWidget && historyInfo.blockMark) {
|
||||
var blockMarkWidget = $tw.utils.findChildNodeInTree(listItemWidget, function(widget) {
|
||||
return widget.blockMarkId === historyInfo.blockMark;
|
||||
});
|
||||
if(anchorWidget) {
|
||||
targetElement = anchorWidget.findAnchorTargetDomNode()
|
||||
foundAnchor = true;
|
||||
if(blockMarkWidget) {
|
||||
targetElement = blockMarkWidget.findBlockMarkTargetDomNode()
|
||||
foundBlockMark = true;
|
||||
}
|
||||
}
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
@ -42,7 +42,7 @@ ClassicStoryView.prototype.navigateTo = function(historyInfo) {
|
||||
return;
|
||||
}
|
||||
// Scroll the node into view
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement, highlight: foundAnchor});
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement, highlight: foundBlockMark});
|
||||
};
|
||||
|
||||
ClassicStoryView.prototype.insert = function(widget) {
|
||||
|
@ -23,15 +23,15 @@ 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 block mark is provided, find the block element that this mark is pointing to
|
||||
var foundBlockMark = false;
|
||||
if(listItemWidget && historyInfo.blockMark) {
|
||||
var blockMarkWidget = $tw.utils.findChildNodeInTree(listItemWidget, function(widget) {
|
||||
return widget.blockMarkId === historyInfo.blockMark;
|
||||
});
|
||||
if(anchorWidget) {
|
||||
targetElement = anchorWidget.findAnchorTargetDomNode()
|
||||
foundAnchor = true;
|
||||
if(blockMarkWidget) {
|
||||
targetElement = blockMarkWidget.findBlockMarkTargetDomNode()
|
||||
foundBlockMark = true;
|
||||
}
|
||||
}
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
@ -39,7 +39,7 @@ PopStoryView.prototype.navigateTo = function(historyInfo) {
|
||||
return;
|
||||
}
|
||||
// Scroll the node into view
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement, highlight: foundAnchor});
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement, highlight: foundBlockMark});
|
||||
};
|
||||
|
||||
PopStoryView.prototype.insert = function(widget) {
|
||||
|
@ -51,14 +51,15 @@ 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 block mark is provided, find the block element that this mark is pointing to
|
||||
var foundBlockMark = false;
|
||||
if(listItemWidget && historyInfo.blockMark) {
|
||||
var blockMarkWidget = $tw.utils.findChildNodeInTree(listItemWidget, function(widget) {
|
||||
return widget.blockMarkId === historyInfo.blockMark;
|
||||
});
|
||||
if(anchorWidget) {
|
||||
anchorElement = anchorWidget.findAnchorTargetDomNode()
|
||||
if(blockMarkWidget) {
|
||||
targetElement = blockMarkWidget.findBlockMarkTargetDomNode()
|
||||
foundBlockMark = true;
|
||||
}
|
||||
}
|
||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||
@ -129,10 +130,7 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
|
||||
},duration);
|
||||
}
|
||||
// Scroll the target into view
|
||||
if(anchorElement) {
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: anchorElement, highlight: true});
|
||||
}
|
||||
// $tw.pageScroller.scrollIntoView(targetElement);
|
||||
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement, highlight: true});
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1,18 +1,18 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/anchor.js
|
||||
title: $:/core/modules/widgets/block-mark.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
An invisible element with anchor id metadata.
|
||||
An invisible element with block-mark id metadata.
|
||||
\*/
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
var AnchorWidget = function(parseTreeNode,options) {
|
||||
var BlockMarkWidget = 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();
|
||||
BlockMarkWidget.prototype = new Widget();
|
||||
|
||||
AnchorWidget.prototype.render = function(parent,nextSibling) {
|
||||
BlockMarkWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Save the parent dom node
|
||||
this.parentDomNode = parent;
|
||||
// Compute our attributes
|
||||
@ -21,13 +21,13 @@ AnchorWidget.prototype.render = function(parent,nextSibling) {
|
||||
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);
|
||||
this.idNode.setAttribute("data-block-mark-id",this.blockMarkId);
|
||||
this.idNode.setAttribute("data-block-mark-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.setAttribute("data-block-mark-previous-sibling","true");
|
||||
}
|
||||
this.idNode.className = "tc-anchor";
|
||||
this.idNode.className = "tc-block-mark";
|
||||
parent.insertBefore(this.idNode,nextSibling);
|
||||
this.domNodes.push(this.idNode);
|
||||
};
|
||||
@ -35,9 +35,9 @@ AnchorWidget.prototype.render = function(parent,nextSibling) {
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
AnchorWidget.prototype.execute = function() {
|
||||
BlockMarkWidget.prototype.execute = function() {
|
||||
// Get the id from the parse tree node or manually assigned attributes
|
||||
this.anchorId = this.getAttribute("id");
|
||||
this.blockMarkId = this.getAttribute("id");
|
||||
this.tiddlerTitle = this.getVariable("currentTiddler");
|
||||
this.previousSibling = this.getAttribute("previousSibling") === "yes";
|
||||
// Make the child widgets
|
||||
@ -45,9 +45,9 @@ AnchorWidget.prototype.execute = function() {
|
||||
};
|
||||
|
||||
/*
|
||||
Find the DOM node pointed by this anchor
|
||||
Find the DOM node pointed by this block mark
|
||||
*/
|
||||
Widget.prototype.findAnchorTargetDomNode = function() {
|
||||
Widget.prototype.findBlockMarkTargetDomNode = function() {
|
||||
if(!this.idNode) {
|
||||
return null;
|
||||
}
|
||||
@ -63,7 +63,7 @@ Widget.prototype.findAnchorTargetDomNode = function() {
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
AnchorWidget.prototype.refresh = function(changedTiddlers) {
|
||||
BlockMarkWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(($tw.utils.count(changedAttributes) > 0)) {
|
||||
this.refreshSelf();
|
||||
@ -73,4 +73,4 @@ AnchorWidget.prototype.refresh = function(changedTiddlers) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.anchor = AnchorWidget;
|
||||
exports["block-mark"] = BlockMarkWidget;
|
@ -160,7 +160,7 @@ LinkWidget.prototype.handleClickEvent = function(event) {
|
||||
this.dispatchEvent({
|
||||
type: "tm-navigate",
|
||||
navigateTo: this.to,
|
||||
toAnchor: this.toAnchor,
|
||||
toBlockMark: this.toBlockMark,
|
||||
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
|
||||
@ -191,7 +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.toBlockMark = this.getAttribute("toBlockMark");
|
||||
this.tooltip = this.getAttribute("tooltip");
|
||||
this["aria-label"] = this.getAttribute("aria-label");
|
||||
this.linkClasses = this.getAttribute("class");
|
||||
|
@ -152,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,event.toAnchor);
|
||||
this.addToHistory(event.navigateTo,event.navigateFromClientRect,event.toBlockMark);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -437,7 +437,7 @@ describe("WikiText parser tests", function() {
|
||||
end: 106,
|
||||
},
|
||||
{
|
||||
type: 'anchor',
|
||||
type: 'blockmark',
|
||||
attributes: {
|
||||
id: { type: 'string', value: 'BlockLevelLinksID1', start: 126, end: 144 },
|
||||
previousSibling: { type: 'string', value: '' },
|
||||
@ -445,7 +445,7 @@ describe("WikiText parser tests", function() {
|
||||
children: [],
|
||||
start: 106,
|
||||
end: 126,
|
||||
rule: 'anchor',
|
||||
rule: 'blockmark',
|
||||
},
|
||||
],
|
||||
start: 0,
|
||||
@ -465,7 +465,7 @@ describe("WikiText parser tests", function() {
|
||||
type: 'link',
|
||||
attributes: {
|
||||
to: { type: 'string', value: 'Block Level Links in WikiText', start: 29, end: 58 },
|
||||
toAnchor: { type: 'string', value: 'BlockLevelLinksID1', start: 59, end: 77 },
|
||||
toBlockMark: { type: 'string', value: 'BlockLevelLinksID1', start: 59, end: 77 },
|
||||
},
|
||||
children: [{ type: 'text', text: 'Link to BlockLevelLinksID1', start: 2, end: 28 }],
|
||||
start: 0,
|
||||
|
@ -2,16 +2,16 @@ caption: block id
|
||||
created: 20230916061829840
|
||||
modified: 20230922150245402
|
||||
tags: Widgets
|
||||
title: AnchorWidget
|
||||
title: BlockMarkWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
! Introduction
|
||||
|
||||
The block id widget make an anchor that can be focused and jump to.
|
||||
The block id widget make an block mark that can be focused and jump to.
|
||||
|
||||
! Content and Attributes
|
||||
|
||||
The content of the `<$anchor>` widget is ignored.
|
||||
The content of the `<$block-mark>` widget is ignored.
|
||||
|
||||
|!Attribute |!Description |
|
||||
|id |The unique id for the block |
|
||||
@ -21,14 +21,14 @@ See [[Block Level Links in WikiText^🤗→AddingIDforblock]] for WikiText synta
|
||||
|
||||
! 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"/>
|
||||
<<wikitext-example-without-html """The block id widget is invisible, and is usually located at the end of the line. ID is here:<$block-mark id="BlockLevelLinksID1"/>
|
||||
|
||||
[[Link to BlockLevelLinksID1|AnchorWidget^BlockLevelLinksID1]]
|
||||
[[Link to BlockLevelLinksID1|BlockMarkWidget^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"/>
|
||||
ID is here:<$block-mark id="BlockLevelLinksID2" previousSibling="yes"/>
|
||||
|
||||
[[Link to BlockLevelLinksID2|AnchorWidget^BlockLevelLinksID2]]
|
||||
[[Link to BlockLevelLinksID2|BlockMarkWidget^BlockLevelLinksID2]]
|
||||
""">>
|
||||
|
@ -16,7 +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]] |
|
||||
|toBlockMark |<<.from-version "5.3.6">> 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]] |
|
||||
|
@ -124,7 +124,7 @@ In TiddlyWiki anchor links can help us link to target points and distinct sectio
|
||||
|
||||
See [[Anchor Links using HTML]] for more information.
|
||||
|
||||
! Linking within tiddlers - Link to block
|
||||
! Linking within tiddlers - Link to block mark
|
||||
|
||||
You can link to a specific block within a tiddler using `^blockId` syntax. You will also get block level backlinks with this technique.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user