mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-02-14 05:59:48 +00:00
Compare commits
4 Commits
fix-transc
...
bind-scrol
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1018a9eb40 | ||
|
|
ce30e64a71 | ||
|
|
3e213569e2 | ||
|
|
4bdac09872 |
@@ -171,6 +171,42 @@ ScrollableWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
parent.insertBefore(this.outerDomNode,nextSibling);
|
parent.insertBefore(this.outerDomNode,nextSibling);
|
||||||
this.renderChildren(this.innerDomNode,null);
|
this.renderChildren(this.innerDomNode,null);
|
||||||
this.domNodes.push(this.outerDomNode);
|
this.domNodes.push(this.outerDomNode);
|
||||||
|
// If the scroll position is bound to a tiddler
|
||||||
|
if(this.scrollableBind) {
|
||||||
|
// After a delay for rendering, scroll to the bound position
|
||||||
|
setTimeout(this.updateScrollPositionFromBoundTiddler.bind(this),50);
|
||||||
|
// Save scroll position on DOM scroll event
|
||||||
|
this.outerDomNode.addEventListener("scroll",function(event) {
|
||||||
|
var existingTiddler = self.wiki.getTiddler(self.scrollableBind),
|
||||||
|
newTiddlerFields = {
|
||||||
|
title: self.scrollableBind,
|
||||||
|
"scroll-left": self.outerDomNode.scrollLeft.toString(),
|
||||||
|
"scroll-top": self.outerDomNode.scrollTop.toString()
|
||||||
|
};
|
||||||
|
if(!existingTiddler || (existingTiddler.fields["scroll-left"] !== newTiddlerFields["scroll-left"] || existingTiddler.fields["scroll-top"] !== newTiddlerFields["scroll-top"])) {
|
||||||
|
self.wiki.addTiddler(new $tw.Tiddler(existingTiddler,newTiddlerFields));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ScrollableWidget.prototype.updateScrollPositionFromBoundTiddler = function() {
|
||||||
|
var tiddler = this.wiki.getTiddler(this.scrollableBind);
|
||||||
|
if(tiddler) {
|
||||||
|
var scrollLeftTo = this.outerDomNode.scrollLeft;
|
||||||
|
if(parseFloat(tiddler.fields["scroll-left"]).toString() === tiddler.fields["scroll-left"]) {
|
||||||
|
scrollLeftTo = parseFloat(tiddler.fields["scroll-left"]);
|
||||||
|
}
|
||||||
|
var scrollTopTo = this.outerDomNode.scrollTop;
|
||||||
|
if(parseFloat(tiddler.fields["scroll-top"]).toString() === tiddler.fields["scroll-top"]) {
|
||||||
|
scrollTopTo = parseFloat(tiddler.fields["scroll-top"]);
|
||||||
|
}
|
||||||
|
this.outerDomNode.scrollTo({
|
||||||
|
top: scrollTopTo,
|
||||||
|
left: scrollLeftTo,
|
||||||
|
behavior: "instant"
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -178,6 +214,7 @@ Compute the internal state of the widget
|
|||||||
*/
|
*/
|
||||||
ScrollableWidget.prototype.execute = function() {
|
ScrollableWidget.prototype.execute = function() {
|
||||||
// Get attributes
|
// Get attributes
|
||||||
|
this.scrollableBind = this.getAttribute("bind");
|
||||||
this.fallthrough = this.getAttribute("fallthrough","yes");
|
this.fallthrough = this.getAttribute("fallthrough","yes");
|
||||||
this["class"] = this.getAttribute("class");
|
this["class"] = this.getAttribute("class");
|
||||||
// Make child widgets
|
// Make child widgets
|
||||||
@@ -193,6 +230,9 @@ ScrollableWidget.prototype.refresh = function(changedTiddlers) {
|
|||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if(changedAttributes.bind || changedTiddlers[this.getAttribute("bind")]) {
|
||||||
|
this.updateScrollPositionFromBoundTiddler();
|
||||||
|
}
|
||||||
return this.refreshChildren(changedTiddlers);
|
return this.refreshChildren(changedTiddlers);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,30 +41,43 @@ TranscludeWidget.prototype.execute = function() {
|
|||||||
this.collectAttributes();
|
this.collectAttributes();
|
||||||
this.collectStringParameters();
|
this.collectStringParameters();
|
||||||
this.collectSlotFillParameters();
|
this.collectSlotFillParameters();
|
||||||
// Get the target text and parse tree nodes that we are transcluding
|
// Determine whether we're being used in inline or block mode
|
||||||
var target = this.getTransclusionTarget(),
|
var parseAsInline = !this.parseTreeNode.isBlock;
|
||||||
parseTreeNodes;
|
if(this.transcludeMode === "inline") {
|
||||||
this.sourceText = target.text;
|
parseAsInline = true;
|
||||||
this.parserType = target.type;
|
} else if(this.transcludeMode === "block") {
|
||||||
this.parseAsInline = target.parseAsInline;
|
parseAsInline = false;
|
||||||
|
}
|
||||||
// Set 'thisTiddler'
|
// Set 'thisTiddler'
|
||||||
this.setVariable("thisTiddler",this.transcludeTitle);
|
this.setVariable("thisTiddler",this.transcludeTitle);
|
||||||
|
var parseTreeNodes, target;
|
||||||
// Process the transclusion according to the output type
|
// Process the transclusion according to the output type
|
||||||
switch(this.transcludeOutput || "text/html") {
|
switch(this.transcludeOutput || "text/html") {
|
||||||
case "text/html":
|
case "text/html":
|
||||||
// Return the parse tree nodes
|
// Return the parse tree nodes of the target
|
||||||
|
target = this.parseTransclusionTarget(parseAsInline);
|
||||||
|
this.parseAsInline = target.parseAsInline;
|
||||||
parseTreeNodes = target.parseTreeNodes;
|
parseTreeNodes = target.parseTreeNodes;
|
||||||
break;
|
break;
|
||||||
case "text/raw":
|
case "text/raw":
|
||||||
// Just return the raw text
|
// Just return the raw text
|
||||||
parseTreeNodes = [{type: "text", text: this.sourceText}];
|
target = this.getTransclusionTarget();
|
||||||
|
parseTreeNodes = [{type: "text", text: target.text}];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// text/plain
|
// "text/plain" is the plain text result of wikifying the text
|
||||||
var plainText = this.wiki.renderText("text/plain",this.parserType,this.sourceText,{parentWidget: this});
|
target = this.parseTransclusionTarget(parseAsInline);
|
||||||
parseTreeNodes = [{type: "text", text: plainText}];
|
var widgetNode = this.wiki.makeWidget(target.parser,{
|
||||||
|
parentWidget: this,
|
||||||
|
document: $tw.fakeDocument
|
||||||
|
});
|
||||||
|
var container = $tw.fakeDocument.createElement("div");
|
||||||
|
widgetNode.render(container,null);
|
||||||
|
parseTreeNodes = [{type: "text", text: container.textContent}];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this.sourceText = target.text;
|
||||||
|
this.parserType = target.type;
|
||||||
// Set the legacy transclusion context variables only if we're not transcluding a variable
|
// Set the legacy transclusion context variables only if we're not transcluding a variable
|
||||||
if(!this.transcludeVariable) {
|
if(!this.transcludeVariable) {
|
||||||
var recursionMarker = this.makeRecursionMarker();
|
var recursionMarker = this.makeRecursionMarker();
|
||||||
@@ -161,17 +174,44 @@ TranscludeWidget.prototype.collectSlotFillParameters = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get transcluded parse tree nodes as an object {text:,type:,parseTreeNodes:,parseAsInline:}
|
Get transcluded details as an object {text:,type:}
|
||||||
*/
|
*/
|
||||||
TranscludeWidget.prototype.getTransclusionTarget = function() {
|
TranscludeWidget.prototype.getTransclusionTarget = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
// Determine whether we're being used in inline or block mode
|
var text;
|
||||||
var parseAsInline = !this.parseTreeNode.isBlock;
|
// Return the text and type of the target
|
||||||
if(this.transcludeMode === "inline") {
|
if(this.hasAttribute("$variable")) {
|
||||||
parseAsInline = true;
|
if(this.transcludeVariable) {
|
||||||
} else if(this.transcludeMode === "block") {
|
// Transcluding a variable
|
||||||
parseAsInline = false;
|
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()});
|
||||||
|
text = variableInfo.text;
|
||||||
|
return {
|
||||||
|
text: variableInfo.text,
|
||||||
|
type: this.transcludeType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Transcluding a text reference
|
||||||
|
var parserInfo = this.wiki.getTextReferenceParserInfo(
|
||||||
|
this.transcludeTitle,
|
||||||
|
this.transcludeField,
|
||||||
|
this.transcludeIndex,
|
||||||
|
{
|
||||||
|
subTiddler: this.transcludeSubTiddler,
|
||||||
|
defaultType: this.transcludeType
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
text: parserInfo.text,
|
||||||
|
type: parserInfo.type
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get transcluded parse tree nodes as an object {text:,type:,parseTreeNodes:,parseAsInline:}
|
||||||
|
*/
|
||||||
|
TranscludeWidget.prototype.parseTransclusionTarget = function(parseAsInline) {
|
||||||
|
var self = this;
|
||||||
var parser;
|
var parser;
|
||||||
// Get the parse tree
|
// Get the parse tree
|
||||||
if(this.hasAttribute("$variable")) {
|
if(this.hasAttribute("$variable")) {
|
||||||
@@ -237,7 +277,7 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
|
|||||||
}
|
}
|
||||||
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],name,param["default"])
|
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],name,param["default"])
|
||||||
});
|
});
|
||||||
} else if(srcVariable && (srcVariable.isMacroDefinition || !srcVariable.isFunctionDefinition)) {
|
} else if(srcVariable && !srcVariable.isFunctionDefinition) {
|
||||||
// For macros and ordinary variables, wrap the parse tree in a vars widget assigning the parameters to variables named "__paramname__"
|
// For macros and ordinary variables, wrap the parse tree in a vars widget assigning the parameters to variables named "__paramname__"
|
||||||
parser = {
|
parser = {
|
||||||
tree: [
|
tree: [
|
||||||
@@ -269,22 +309,13 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Return the parse tree
|
// Return the parse tree
|
||||||
if(parser) {
|
return {
|
||||||
return {
|
parser: parser,
|
||||||
parseTreeNodes: parser.tree,
|
parseTreeNodes: parser ? parser.tree : (this.slotFillParseTrees["ts-missing"] || []),
|
||||||
parseAsInline: parseAsInline,
|
parseAsInline: parseAsInline,
|
||||||
text: parser.source,
|
text: parser && parser.source,
|
||||||
type: parser.type
|
type: parser && parser.type
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
// If there's no parse tree then return the missing slot value
|
|
||||||
return {
|
|
||||||
parseTreeNodes: (this.slotFillParseTrees["ts-missing"] || []),
|
|
||||||
parseAsInline: parseAsInline,
|
|
||||||
text: null,
|
|
||||||
type: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ type: text/vnd.tiddlywiki
|
|||||||
|
|
||||||
! Overview of v5.3.1
|
! Overview of v5.3.1
|
||||||
|
|
||||||
! Reversions of v5.3.0 Changes
|
! Bug Fixes and Reversions of v5.3.0 Changes
|
||||||
|
|
||||||
* Reverted adding the `widget.destroy()` method because of performance concerns (see https://github.com/Jermolene/TiddlyWiki5/pull/7468)
|
* Reverted adding the `widget.destroy()` method because of performance concerns (see https://github.com/Jermolene/TiddlyWiki5/pull/7468)
|
||||||
|
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7647">> inefficiency when transcluding with the ''$output'' attribute set to `text/plain`
|
||||||
|
|
||||||
! Plugin Improvements
|
! Plugin Improvements
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
title: $:/my-scroll-position
|
||||||
|
scroll-left: 0
|
||||||
|
scroll-top: 100
|
||||||
@@ -33,4 +33,4 @@ $param$ with a ''buffalo''
|
|||||||
+
|
+
|
||||||
title: ExpectedResult
|
title: ExpectedResult
|
||||||
|
|
||||||
<p>Going to lunch with a ''buffalo''</p><p>Going to breakfastwith a<strong>buffalo</strong></p><p>Going to dinner with a <strong>buffalo</strong></p>Going to lunch with a buffalo with a buffaloGoing to dinner with a buffalo
|
<p>Going to lunch with a ''buffalo''</p><p>Going to breakfastwith a<strong>buffalo</strong></p><p>Going to dinner with a <strong>buffalo</strong></p>Going to lunch with a ''buffalo''Going to breakfastwith abuffaloGoing to dinner with a buffalo
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
title: Procedures/Double/Underscore
|
||||||
|
description: Checking that procedures don't expose parameters as variables wrapped in double underscores
|
||||||
|
type: text/vnd.tiddlywiki-multiple
|
||||||
|
tags: [[$:/tags/wiki-test-spec]]
|
||||||
|
|
||||||
|
title: Output
|
||||||
|
|
||||||
|
\whitespace trim
|
||||||
|
\procedure mamacro(one:"red",two:"green")
|
||||||
|
It is $one$ and $two$<<__one__>><<__two__>>.
|
||||||
|
\end
|
||||||
|
|
||||||
|
<$macrocall $name="mamacro"/>
|
||||||
|
|
||||||
|
<$transclude $variable="mamacro"/>
|
||||||
|
|
||||||
|
<$transclude $variable="mamacro" one="orange"/>
|
||||||
|
|
||||||
|
<$transclude $variable="mamacro" 0="pink"/>
|
||||||
|
|
||||||
|
<$transclude $variable="mamacro" one="purple" 1="pink"/>
|
||||||
|
|
||||||
|
+
|
||||||
|
title: ExpectedResult
|
||||||
|
|
||||||
|
<p>It is $one$ and $two$.</p><p>It is $one$ and $two$.</p><p>It is $one$ and $two$.</p><p>It is $one$ and $two$.</p><p>It is $one$ and $two$.</p>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
caption: scrollable
|
caption: scrollable
|
||||||
created: 20140324223413403
|
created: 20140324223413403
|
||||||
modified: 20220620115347910
|
modified: 20230731100903977
|
||||||
tags: Widgets
|
tags: Widgets
|
||||||
title: ScrollableWidget
|
title: ScrollableWidget
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
@@ -16,12 +16,15 @@ The content of the `<$scrollable>` widget is displayed within a pair of wrapper
|
|||||||
|!Attribute |!Description |
|
|!Attribute |!Description |
|
||||||
|class |The CSS class(es) to be applied to the outer DIV |
|
|class |The CSS class(es) to be applied to the outer DIV |
|
||||||
|fallthrough |See below |
|
|fallthrough |See below |
|
||||||
|
|bind |<<.from-version "5.3.2">> Optional title of tiddler to which the scroll position should be bound |
|
||||||
|
|
||||||
|
Binding the scroll position to a tiddler automatically copies the scroll coordinates into the `scroll-left` and `scroll-top` fields as scrolling occurs. Conversely, setting those field values will automatically cause the scrollable to scroll if it can.
|
||||||
|
|
||||||
<$macrocall $name=".note" _="""If a scrollable widget can't handle the `tm-scroll` message because the inner DIV fits within the outer DIV, then by default the message falls through to the parent widget. Setting the ''fallthrough'' attribute to `no` prevents this behaviour."""/>
|
<$macrocall $name=".note" _="""If a scrollable widget can't handle the `tm-scroll` message because the inner DIV fits within the outer DIV, then by default the message falls through to the parent widget. Setting the ''fallthrough'' attribute to `no` prevents this behaviour."""/>
|
||||||
|
|
||||||
! Examples
|
! Examples
|
||||||
|
|
||||||
This example requires the following CSS definitions from [[$:/_tw5.com-styles]]:
|
These examples require the following CSS definitions from [[$:/_tw5.com-styles]]:
|
||||||
|
|
||||||
```
|
```
|
||||||
.tc-scrollable-demo {
|
.tc-scrollable-demo {
|
||||||
@@ -33,6 +36,8 @@ This example requires the following CSS definitions from [[$:/_tw5.com-styles]]:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!! Simple Usage
|
||||||
|
|
||||||
This wiki text shows how to display a list within the scrollable widget:
|
This wiki text shows how to display a list within the scrollable widget:
|
||||||
|
|
||||||
<<wikitext-example-without-html "<$scrollable class='tc-scrollable-demo'>
|
<<wikitext-example-without-html "<$scrollable class='tc-scrollable-demo'>
|
||||||
@@ -46,3 +51,23 @@ This wiki text shows how to display a list within the scrollable widget:
|
|||||||
</$scrollable>
|
</$scrollable>
|
||||||
">>
|
">>
|
||||||
|
|
||||||
|
!! Binding scroll position to a tiddler
|
||||||
|
|
||||||
|
[[Current scroll position|$:/my-scroll-position]]: {{$:/my-scroll-position!!scroll-left}}, {{$:/my-scroll-position!!scroll-top}}
|
||||||
|
|
||||||
|
<$button>
|
||||||
|
<$action-setfield $tiddler="$:/my-scroll-position" scroll-left="100" scroll-top="100"/>
|
||||||
|
Set current scroll position to 100,100
|
||||||
|
</$button>
|
||||||
|
|
||||||
|
<<wikitext-example-without-html "<$scrollable class='tc-scrollable-demo' bind='$:/my-scroll-position'>
|
||||||
|
<$list filter='[tag[Reference]]'>
|
||||||
|
|
||||||
|
<$view field='title'/>: <$list filter='[all[current]links[]sort[title]]' storyview='pop'>
|
||||||
|
<$link><$view field='title'/></$link>
|
||||||
|
</$list>
|
||||||
|
|
||||||
|
</$list>
|
||||||
|
</$scrollable>
|
||||||
|
">>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user