1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-12-24 17:10:29 +00:00

Refactor $parameters widget

The objective is to add a $depth attribute so that it is possible to reach up to retrieve the parameters of ancestor transclusions. However, doing so requires changing the encoding of parameter names so that it is not possible for a user parameter to clash with an attribute like $depth. So now we have to double up dollars on any attribute names seen by the parameters widget, just like with the transclude widget itself.
This commit is contained in:
jeremy@jermolene.com 2022-05-31 09:03:20 +01:00
parent 150266c731
commit 006ae6e759
8 changed files with 142 additions and 62 deletions

View File

@ -40,8 +40,13 @@ exports.parse = function() {
var attributes = Object.create(null), var attributes = Object.create(null),
orderedAttributes = []; orderedAttributes = [];
$tw.utils.each(params,function(param) { $tw.utils.each(params,function(param) {
var attribute = {name: param.name, type: "string", value: param["default"] || ""}; var name = param.name;
attributes[param.name] = attribute; // Parameter names starting with dollar must be escaped to double dollars for the parameters widget
if(name.charAt(0) === "$") {
name = "$" + name;
}
var attribute = {name: name, type: "string", value: param["default"] || ""};
attributes[name] = attribute;
orderedAttributes.push(attribute); orderedAttributes.push(attribute);
}); });
// Save the macro definition // Save the macro definition

View File

@ -42,21 +42,41 @@ Compute the internal state of the widget
*/ */
ParametersWidget.prototype.execute = function() { ParametersWidget.prototype.execute = function() {
var self = this; var self = this;
// Find the parent transclusion this.parametersDepth = parseInt(this.getAttribute("$depth","1"),10) || 1;
var transclusionWidget = this.parentWidget; // Find the parent transclusions
while(transclusionWidget && !(transclusionWidget instanceof TranscludeWidget)) { var pointer = this.parentWidget,
transclusionWidget = transclusionWidget.parentWidget; depth = this.parametersDepth;
while(pointer) {
if(pointer instanceof TranscludeWidget) {
depth--;
if(depth === 0) {
break;
}
}
pointer = pointer.parentWidget;
} }
// Process each parameter // Process each parameter
if(transclusionWidget) { if(pointer instanceof TranscludeWidget) {
// Get the value for each defined parameter
$tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(self.parseTreeNode),function(attr,index) { $tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(self.parseTreeNode),function(attr,index) {
var name = attr.name, var name = attr.name;
value = transclusionWidget.getTransclusionParameter(name,index,self.getAttribute(name,"")); // If the attribute name starts with $$ then reduce to a single dollar
self.setVariable(name,value); if(name.substr(0,2) === "$$") {
}); name = name.substr(1);
$tw.utils.each(transclusionWidget.getTransclusionMetaVariables(),function(value,name) { }
var value = pointer.getTransclusionParameter(name,index,self.getAttribute(attr.name,""));
self.setVariable(name,value); self.setVariable(name,value);
}); });
// Assign any metaparameters
var assignMetaParameter = function(name) {
var variableName = self.getAttribute("$" + name);
if(variableName !== undefined) {
self.setVariable(variableName,pointer.getTransclusionMetaParameter(name));
}
};
assignMetaParameter("parseAsInline");
assignMetaParameter("parseTreeNodes");
assignMetaParameter("params");
} }
// Construct the child widgets // Construct the child widgets
this.makeChildWidgets(); this.makeChildWidgets();

View File

@ -198,7 +198,12 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
type: parser.type type: parser.type
} }
$tw.utils.each(srcVariable.params,function(param) { $tw.utils.each(srcVariable.params,function(param) {
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],param.name,param["default"]) var name = param.name;
// Parameter names starting with dollar must be escaped to double dollars
if(name.charAt(0) === "$") {
name = "$" + name;
}
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],name,param["default"])
}); });
} else { } else {
// 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__"
@ -299,14 +304,19 @@ TranscludeWidget.prototype.getTransclusionParameter = function(name,index,defaul
}; };
/* /*
Get a hashmap of the special variables to be provided by the parameters widget Get one of the special parameters to be provided by the parameters widget
*/ */
TranscludeWidget.prototype.getTransclusionMetaVariables = function() { TranscludeWidget.prototype.getTransclusionMetaParameter = function(name) {
var variables = { switch(name) {
"@parseAsInline": this.parseAsInline ? "yes" : "no", case "parseAsInline":
"@params": JSON.stringify(this.stringParametersByName) return this.parseAsInline ? "yes" : "no";
}; case "parseTreeNodes":
return variables; return JSON.stringify(this.parseTreeNode);
case "params":
return JSON.stringify(this.stringParametersByName);
default:
return "";
}
}; };
/* /*

View File

@ -5,41 +5,44 @@ Import this component to make all the child transclusions visible.
Block transclusions are shown in red, and inline transclusions are shown in green. Block transclusions are shown in red, and inline transclusions are shown in green.
--> -->
\widget $transclude(tiddler,$tiddler,mode,$mode) \widget $transclude
<!-- Replicate the logic of the transclude widget to determine the output mode, and hence the tag and colour to use for output --> <!-- Use a parameters widget so that we can access the `$params` data -->
<$let <$parameters tiddler="" $$tiddler="" mode="" $$mode="" $params="@params">
mode={{{ [[$mode]is[variable]then<$mode>!is[blank]] :else[[mode]is[variable]then<mode>!is[blank]] :else[<parseAsInline>match[yes]then[inline]else[block]] }}} <!-- Replicate the logic of the transclude widget to determine the output mode, and hence the tag and colour to use for output -->
outputTag={{{ [<mode>match[inline]then[span]else[div]] }}} <$let
outputColour={{{ [<mode>match[inline]then[green]else[red]] }}} mode={{{ [[$mode]is[variable]then<$mode>!is[blank]] :else[[mode]is[variable]then<mode>!is[blank]] :else[<parseAsInline>match[yes]then[inline]else[block]] }}}
> outputTag={{{ [<mode>match[inline]then[span]else[div]] }}}
<!-- Use divs or spans according to the mode --> outputColour={{{ [<mode>match[inline]then[green]else[red]] }}}
<$genesis $type="element" $tag=<<outputTag>> style="color:white;padding:4px;" style.background=<<outputColour>>> >
<$genesis $type="element" $tag=<<outputTag>> style="display: inline-block;"> <!-- Use divs or spans according to the mode -->
<div style="background:white;color:black;font-size: 12px;line-height:1.2;text-align:left;font-weight:normal;padding:4px;margin:4px;"> <$genesis $type="element" $tag=<<outputTag>> style="color:white;padding:4px;" style.background=<<outputColour>>>
<!-- Render the parameters to the transclusion --> <$genesis $type="element" $tag=<<outputTag>> style="display: inline-block;">
<$list filter="[<@params>jsonindexes[]]" emptyMessage="(none)"> <div style="background:white;color:black;font-size: 12px;line-height:1.2;text-align:left;font-weight:normal;padding:4px;margin:4px;">
<div> <!-- Render the parameters to the transclusion -->
<$text text=<<currentTiddler>>/><$text text=": "/><$text text={{{ [<@params>jsonget<currentTiddler>] }}}/> <$list filter="[<@params>jsonindexes[]]" emptyMessage="(none)">
</div> <div>
<$text text=<<currentTiddler>>/><$text text=": "/><$text text={{{ [<@params>jsonget<currentTiddler>] }}}/>
</div>
</$list>
</div>
</$genesis>
<$genesis $type="element" $tag=<<outputTag>> style="background:white;color:black;padding:4px;">
<!-- Look for a parameter starting with $ to determine if we are in legacy mode -->
<$list filter="[<@params>jsonindexes[]] :filter[<currentTiddler>prefix[$]] +[limit[1]]" variable="ignore" emptyMessage="""
<!-- Legacy mode: we render the transclusion without a dollar sign for recursionMarker and mode -->
<$genesis $type="transclude" $remappable="no" $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>]" recursionMarker="no" mode=<<mode>>>
<!-- Reach back up to the grandparent transclusion to get the correct slot value -->
<$slot $name="ts-raw" $depth="2"/>
</$genesis>
""">
<!-- Non-legacy mode: we use dollar signs for the recursionMarker and mode -->
<$genesis $type="transclude" $remappable="no" $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>]" $$recursionMarker="no" $$mode=<<mode>>>
<!-- Reach back up to the grandparent transclusion to get the correct slot fill value -->
<$slot $name="ts-raw" $depth="2"/>
</$genesis>
</$list> </$list>
</div> </$genesis>
</$genesis> </$genesis>
<$genesis $type="element" $tag=<<outputTag>> style="background:white;color:black;padding:4px;"> </$let>
<!-- Look for a parameter starting with $ to determine if we are in legacy mode --> </$parameters>
<$list filter="[<@params>jsonindexes[]] :filter[<currentTiddler>prefix[$]] +[limit[1]]" variable="ignore" emptyMessage="""
<!-- Legacy mode: we render the transclusion without a dollar sign for recursionMarker and mode -->
<$genesis $type="transclude" $remappable="no" $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>]" recursionMarker="no" mode=<<mode>>>
<!-- Reach back up to the grandparent transclusion to get the correct slot value -->
<$slot $name="ts-raw" $depth="2"/>
</$genesis>
""">
<!-- Non-legacy mode: we use dollar signs for the recursionMarker and mode -->
<$genesis $type="transclude" $remappable="no" $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>]" $$recursionMarker="no" $$mode=<<mode>>>
<!-- Reach back up to the grandparent transclusion to get the correct slot fill value -->
<$slot $name="ts-raw" $depth="2"/>
</$genesis>
</$list>
</$genesis>
</$genesis>
<$let>
\end \end

View File

@ -8,9 +8,11 @@ title: Output
\whitespace trim \whitespace trim
\widget $let \widget $let
\whitespace trim \whitespace trim
<$parameters $params="@params">
<$setmultiplevariables $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>addprefix[--]addsuffix[--]]"> <$setmultiplevariables $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>addprefix[--]addsuffix[--]]">
<$slot $name="ts-body"/> <$slot $name="ts-body"/>
</$setmultiplevariables> </$setmultiplevariables>
</$parameters>
\end \end
<$let <$let
one="Elephant" one="Elephant"

View File

@ -0,0 +1,34 @@
title: Transclude/Parameterised/Depth
description: Parameterised transclusion using the $depth attribute
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
<$transclude $tiddler='TiddlerOne' one='Ferret'/>
|
<$transclude $tiddler='TiddlerOne'/>
|
<$transclude $tiddler='TiddlerOne' one='Ferret' $$two="Osprey"/>
|
<$transclude $tiddler='TiddlerOne' $$two="Falcon"/>
+
title: TiddlerOne
\whitespace trim
{{TiddlerTwo}}
+
title: TiddlerTwo
\whitespace trim
<$parameters one='Jaguar' $$two='Piranha' $depth="2">
<$text text=<<one>>/>:<$text text=<<$two>>/>
</$parameters>
<$parameters one='Leopard' $$two='Coelacanth'>
(<$text text=<<one>>/>|<$text text=<<$two>>/>)
</$parameters>
+
title: ExpectedResult
<p>Ferret:Piranha(Leopard|Coelacanth)|Jaguar:Piranha(Leopard|Coelacanth)|Ferret:Osprey(Leopard|Coelacanth)|Jaguar:Falcon(Leopard|Coelacanth)</p>

View File

@ -17,17 +17,18 @@ title: Output
title: TiddlerOne title: TiddlerOne
\whitespace trim \whitespace trim
\parameters(zero:'Jaguar',one:'Lizard',two:'Mole') <$parameters zero='Jaguar' $$one='Lizard' two='Mole' $params="@params">
<$list filter="[<@params>jsonindexes[]]"> <$list filter="[<@params>jsonindexes[]]">
{<$text text=<<currentTiddler>>/>: <$text text={{{ [<@params>jsonget<currentTiddler>] }}}/>} {<$text text=<<currentTiddler>>/>: <$text text={{{ [<@params>jsonget<currentTiddler>] }}}/>}
</$list> </$list>
</$parameters>
+ +
title: TiddlerTwo title: TiddlerTwo
\whitespace trim \whitespace trim
\parameters(zero:'Mouse',one:'Horse',two:'Owl') \parameters(zero:'Mouse',$one:'Horse',two:'Owl')
(<$transclude $tiddler=<<currentTiddler>> zero=<<zero>> one=<<one>> two=<<two>>/>) (<$transclude $tiddler=<<currentTiddler>> zero=<<zero>> $$one=<<$one>> two=<<two>>/>)
+ +
title: ExpectedResult title: ExpectedResult
<p>{0:}{1:}{2:}</p><p></p><p>{0:Ferret}</p><p>{0:Butterfly}{1:Moth}</p><p>{0:Beetle}{1:Scorpion}{2:Snake}</p><p>({one:Scorpion}{two:Snake}{zero:Beetle})</p> <p>{0:}{1:}{2:}</p><p></p><p>{0:Ferret}</p><p>{0:Butterfly}{1:Moth}</p><p>{0:Beetle}{1:Scorpion}{2:Snake}</p><p>({$one:Scorpion}{two:Snake}{zero:Beetle})</p>

View File

@ -7,15 +7,20 @@ title: Output
\whitespace trim \whitespace trim
<$transclude $tiddler='TiddlerOne' one='Ferret'/> <$transclude $tiddler='TiddlerOne' one='Ferret'/>
|
<$transclude $tiddler='TiddlerOne'/> <$transclude $tiddler='TiddlerOne'/>
|
<$transclude $tiddler='TiddlerOne' one='Ferret' $$two="Osprey"/>
|
<$transclude $tiddler='TiddlerOne' $$two="Falcon"/>
+ +
title: TiddlerOne title: TiddlerOne
\whitespace trim \whitespace trim
<$parameters one='Jaguar'> <$parameters one='Jaguar' $$two='Piranha'>
<$text text=<<one>>/> <$text text=<<one>>/>:<$text text=<<$two>>/>
</$parameters> </$parameters>
+ +
title: ExpectedResult title: ExpectedResult
<p>FerretJaguar</p> <p>Ferret:Piranha|Jaguar:Piranha|Ferret:Osprey|Jaguar:Falcon</p>