mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-02-03 20:59:09 +00:00
Fixes to enable the transclude widget itself to be overridden
There are two big changes here: Replace the previous "ts-wrapper" mechanism, which we had been using to redefine custom widgets inside their definitions to prevent recursive calls. Now we've got the genesis widget we can instead control recursion through a new "$remappable" attribute that allows the custom widget mechanism to be skipped. We also extend the slot widget to allow a depth to be specified; it then reaches up by the indicated number of transclusion widgets to find the one from which it should retrieve the slot value.
This commit is contained in:
parent
35430d09ed
commit
f307f00e32
@ -12,8 +12,13 @@ Parse tree utility functions.
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add attribute to parse tree node
|
||||||
|
Can be invoked as (node,name,value) or (node,attr)
|
||||||
|
*/
|
||||||
exports.addAttributeToParseTreeNode = function(node,name,value) {
|
exports.addAttributeToParseTreeNode = function(node,name,value) {
|
||||||
var attribute = {name: name, type: "string", value: value};
|
var attribute = typeof name === "object" ? name : {name: name, type: "string", value: value};
|
||||||
|
name = attribute.name;
|
||||||
node.attributes = node.attributes || {};
|
node.attributes = node.attributes || {};
|
||||||
node.orderedAttributes = node.orderedAttributes || [];
|
node.orderedAttributes = node.orderedAttributes || [];
|
||||||
node.attributes[name] = attribute;
|
node.attributes[name] = attribute;
|
||||||
|
@ -41,6 +41,7 @@ GenesisWidget.prototype.execute = function() {
|
|||||||
// Collect attributes
|
// Collect attributes
|
||||||
this.genesisType = this.getAttribute("$type","element");
|
this.genesisType = this.getAttribute("$type","element");
|
||||||
this.genesisTag = this.getAttribute("$tag","div");
|
this.genesisTag = this.getAttribute("$tag","div");
|
||||||
|
this.genesisRemappable = this.getAttribute("$remappable","yes") === "yes";
|
||||||
this.genesisNames = this.getAttribute("$names","");
|
this.genesisNames = this.getAttribute("$names","");
|
||||||
this.genesisValues = this.getAttribute("$values","");
|
this.genesisValues = this.getAttribute("$values","");
|
||||||
// Construct parse tree
|
// Construct parse tree
|
||||||
@ -49,7 +50,8 @@ GenesisWidget.prototype.execute = function() {
|
|||||||
tag: this.genesisTag,
|
tag: this.genesisTag,
|
||||||
attributes: {},
|
attributes: {},
|
||||||
orderedAttributes: [],
|
orderedAttributes: [],
|
||||||
children: this.parseTreeNode.children || []
|
children: this.parseTreeNode.children || [],
|
||||||
|
isNotRemappable: !this.genesisRemappable
|
||||||
}];
|
}];
|
||||||
// Apply attributes in $names/$values
|
// Apply attributes in $names/$values
|
||||||
this.attributeNames = [];
|
this.attributeNames = [];
|
||||||
|
@ -54,8 +54,9 @@ ParametersWidget.prototype.execute = function() {
|
|||||||
value = transclusionWidget.getTransclusionParameter(name,index,self.getAttribute(name));
|
value = transclusionWidget.getTransclusionParameter(name,index,self.getAttribute(name));
|
||||||
self.setVariable(name,value);
|
self.setVariable(name,value);
|
||||||
});
|
});
|
||||||
this.setVariable("paramNames",$tw.utils.stringifyList(transclusionWidget.getTransclusionParameterNames()));
|
$tw.utils.each(transclusionWidget.getTransclusionMetaVariables(),function(value,name) {
|
||||||
this.setVariable("paramValues",$tw.utils.stringifyList(transclusionWidget.getTransclusionParameterValues()));
|
self.setVariable(name,value);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Construct the child widgets
|
// Construct the child widgets
|
||||||
this.makeChildWidgets();
|
this.makeChildWidgets();
|
||||||
|
@ -43,13 +43,24 @@ Compute the internal state of the widget
|
|||||||
SlotWidget.prototype.execute = function() {
|
SlotWidget.prototype.execute = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.slotName = this.getAttribute("$name");
|
this.slotName = this.getAttribute("$name");
|
||||||
// Find the parent transclusion
|
this.slotDepth = 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.slotDepth;
|
||||||
|
while(pointer) {
|
||||||
|
if(pointer instanceof TranscludeWidget) {
|
||||||
|
depth--;
|
||||||
|
if(depth === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pointer = pointer.parentWidget;
|
||||||
|
}
|
||||||
|
var parseTreeNodes = [{type: "text", attributes: {text: {type: "string", value: "Missing slot reference!"}}}];
|
||||||
|
if(pointer instanceof TranscludeWidget) {
|
||||||
|
// Get the parse tree nodes comprising the slot contents
|
||||||
|
parseTreeNodes = pointer.getTransclusionSlotValue(this.slotName,this.parseTreeNode.children);
|
||||||
}
|
}
|
||||||
// Get the parse tree nodes comprising the slot contents
|
|
||||||
var parseTreeNodes = transclusionWidget.getTransclusionSlotValue(this.slotName,this.parseTreeNode.children);
|
|
||||||
// Construct the child widgets
|
// Construct the child widgets
|
||||||
this.makeChildWidgets(parseTreeNodes);
|
this.makeChildWidgets(parseTreeNodes);
|
||||||
};
|
};
|
||||||
@ -59,7 +70,7 @@ Refresh the widget by ensuring our attributes are up to date
|
|||||||
*/
|
*/
|
||||||
SlotWidget.prototype.refresh = function(changedTiddlers) {
|
SlotWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes();
|
||||||
if(changedAttributes["$name"]) {
|
if(changedAttributes["$name"] || changedAttributes["$depth"]) {
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -46,13 +46,7 @@ TranscludeWidget.prototype.execute = function() {
|
|||||||
parseTreeNodes = target.parseTreeNodes;
|
parseTreeNodes = target.parseTreeNodes;
|
||||||
this.sourceText = target.source;
|
this.sourceText = target.source;
|
||||||
this.sourceType = target.type;
|
this.sourceType = target.type;
|
||||||
// Wrap the transcluded content if required
|
this.parseAsInline = target.parseAsInline;
|
||||||
if(this.slotValueParseTrees["ts-wrapper"]) {
|
|
||||||
this.slotValueParseTrees["ts-wrapped"] = parseTreeNodes;
|
|
||||||
parseTreeNodes = this.slotValueParseTrees["ts-wrapper"];
|
|
||||||
this.sourceTest = undefined;
|
|
||||||
this.sourceType = undefined;
|
|
||||||
}
|
|
||||||
// Set context variables for recursion detection
|
// Set context variables for recursion detection
|
||||||
var recursionMarker = this.makeRecursionMarker();
|
var recursionMarker = this.makeRecursionMarker();
|
||||||
if(this.recursionMarker === "yes") {
|
if(this.recursionMarker === "yes") {
|
||||||
@ -135,6 +129,7 @@ TranscludeWidget.prototype.collectSlotValueParameters = function() {
|
|||||||
if(this.legacyMode) {
|
if(this.legacyMode) {
|
||||||
this.slotValueParseTrees["ts-missing"] = this.parseTreeNode.children;
|
this.slotValueParseTrees["ts-missing"] = this.parseTreeNode.children;
|
||||||
} else {
|
} else {
|
||||||
|
this.slotValueParseTrees["ts-raw"] = this.parseTreeNode.children;
|
||||||
var noValueWidgetsFound = true,
|
var noValueWidgetsFound = true,
|
||||||
searchParseTreeNodes = function(nodes) {
|
searchParseTreeNodes = function(nodes) {
|
||||||
$tw.utils.each(nodes,function(node) {
|
$tw.utils.each(nodes,function(node) {
|
||||||
@ -171,11 +166,11 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
|
|||||||
if(this.transcludeVariable) {
|
if(this.transcludeVariable) {
|
||||||
var variableInfo = this.getVariableInfo(this.transcludeVariable).srcVariable;
|
var variableInfo = this.getVariableInfo(this.transcludeVariable).srcVariable;
|
||||||
if(variableInfo) {
|
if(variableInfo) {
|
||||||
var mode = this.parseTreeNode.isBlock ? "blockParser" : "inlineParser";
|
var mode = parseAsInline ? "inlineParser" : "blockParser";
|
||||||
if(variableInfo[mode]) {
|
if(variableInfo[mode]) {
|
||||||
parser = variableInfo[mode];
|
parser = variableInfo[mode];
|
||||||
} else {
|
} else {
|
||||||
parser = this.wiki.parseText(this.transcludeType,variableInfo.value || "",{parseAsInline: !this.parseTreeNode.isBlock});
|
parser = this.wiki.parseText(this.transcludeType,variableInfo.value || "",{parseAsInline: parseAsInline});
|
||||||
variableInfo[mode] = parser;
|
variableInfo[mode] = parser;
|
||||||
}
|
}
|
||||||
if(parser && variableInfo.isFunctionDefinition) {
|
if(parser && variableInfo.isFunctionDefinition) {
|
||||||
@ -206,6 +201,7 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
|
|||||||
return {
|
return {
|
||||||
parser: parser,
|
parser: parser,
|
||||||
parseTreeNodes: parser.tree,
|
parseTreeNodes: parser.tree,
|
||||||
|
parseAsInline: parseAsInline,
|
||||||
text: parser.source,
|
text: parser.source,
|
||||||
type: parser.type
|
type: parser.type
|
||||||
};
|
};
|
||||||
@ -213,6 +209,7 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
|
|||||||
return {
|
return {
|
||||||
parser: null,
|
parser: null,
|
||||||
parseTreeNodes: (this.slotValueParseTrees["ts-missing"] || []),
|
parseTreeNodes: (this.slotValueParseTrees["ts-missing"] || []),
|
||||||
|
parseAsInline: parseAsInline,
|
||||||
text: null,
|
text: null,
|
||||||
type: null
|
type: null
|
||||||
};
|
};
|
||||||
@ -234,6 +231,17 @@ TranscludeWidget.prototype.getTransclusionParameter = function(name,index,defaul
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get a hashmap of the special variables to be provided by the parameters widget
|
||||||
|
*/
|
||||||
|
TranscludeWidget.prototype.getTransclusionMetaVariables = function() {
|
||||||
|
return {
|
||||||
|
paramNames: $tw.utils.stringifyList(this.getTransclusionParameterNames()),
|
||||||
|
paramValues: $tw.utils.stringifyList(this.getTransclusionParameterValues()),
|
||||||
|
parseAsInline: this.parseAsInline ? "yes" : "no"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get an array of the names of all the provided transclusion parameters
|
Get an array of the names of all the provided transclusion parameters
|
||||||
*/
|
*/
|
||||||
@ -248,7 +256,7 @@ TranscludeWidget.prototype.getTransclusionParameterValues = function() {
|
|||||||
var self = this,
|
var self = this,
|
||||||
values = [];
|
values = [];
|
||||||
$tw.utils.each(Object.keys(this.stringParametersByName),function(name) {
|
$tw.utils.each(Object.keys(this.stringParametersByName),function(name) {
|
||||||
values.push(self.stringParametersByName[name]);
|
values.push(self.stringParametersByName[name] || "");
|
||||||
});
|
});
|
||||||
return values;
|
return values;
|
||||||
};
|
};
|
||||||
@ -282,6 +290,7 @@ TranscludeWidget.prototype.makeRecursionMarker = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TranscludeWidget.prototype.parserNeedsRefresh = function() {
|
TranscludeWidget.prototype.parserNeedsRefresh = function() {
|
||||||
|
// TODO: Doesn't consider transcluded variables
|
||||||
var parserInfo = this.wiki.getTextReferenceParserInfo(this.transcludeTitle,this.transcludeField,this.transcludeIndex,{subTiddler:this.transcludeSubTiddler});
|
var parserInfo = this.wiki.getTextReferenceParserInfo(this.transcludeTitle,this.transcludeField,this.transcludeIndex,{subTiddler:this.transcludeSubTiddler});
|
||||||
return (this.sourceText === undefined || parserInfo.sourceText !== this.sourceText || parserInfo.parserType !== this.parserType)
|
return (this.sourceText === undefined || parserInfo.sourceText !== this.sourceText || parserInfo.parserType !== this.parserType)
|
||||||
};
|
};
|
||||||
|
@ -401,49 +401,23 @@ Widget.prototype.makeChildWidget = function(parseTreeNode,options) {
|
|||||||
options = options || {};
|
options = options || {};
|
||||||
// Check whether this node type is defined by a custom macro definition
|
// Check whether this node type is defined by a custom macro definition
|
||||||
var variableDefinitionName = "<$" + parseTreeNode.type + ">";
|
var variableDefinitionName = "<$" + parseTreeNode.type + ">";
|
||||||
if(parseTreeNode.type !== "transclude" && this.variables[variableDefinitionName] && this.variables[variableDefinitionName].value) {
|
if(!parseTreeNode.isNotRemappable && this.variables[variableDefinitionName] && this.variables[variableDefinitionName].value) {
|
||||||
var newParseTreeNode = {
|
var newParseTreeNode = {
|
||||||
type: "transclude",
|
type: "transclude",
|
||||||
attributes: {
|
|
||||||
"$variable": {name: "$variable", type: "string", value: variableDefinitionName}
|
|
||||||
},
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: "value",
|
type: "value",
|
||||||
attributes: {
|
|
||||||
"$name": {name: "$name", type: "string", value: "ts-body"}
|
|
||||||
},
|
|
||||||
children: parseTreeNode.children
|
children: parseTreeNode.children
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "value",
|
|
||||||
attributes: {
|
|
||||||
"$name": {name: "$name", type: "string", value: "ts-wrapper"}
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: "setvariable",
|
|
||||||
attributes: {
|
|
||||||
"name": {name: "name", type: "string", value: variableDefinitionName},
|
|
||||||
"value": {name: "value", type: "string", value: ""}
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: "slot",
|
|
||||||
attributes: {
|
|
||||||
"$name": {name: "$name", type: "string", value: "ts-wrapped"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
isBlock: parseTreeNode.isBlock
|
||||||
};
|
};
|
||||||
|
$tw.utils.addAttributeToParseTreeNode(newParseTreeNode,"$variable",variableDefinitionName);
|
||||||
|
$tw.utils.addAttributeToParseTreeNode(newParseTreeNode.children[0],"$name","ts-body");
|
||||||
$tw.utils.each(parseTreeNode.attributes,function(attr,name) {
|
$tw.utils.each(parseTreeNode.attributes,function(attr,name) {
|
||||||
// If the attribute starts with a dollar then add an extra dollar so that it doesn't clash with the $xxx attributes of transclude
|
// If the attribute starts with a dollar then add an extra dollar so that it doesn't clash with the $xxx attributes of transclude
|
||||||
name = name.charAt(0) === "$" ? "$" + name : name;
|
name = name.charAt(0) === "$" ? "$" + name : name;
|
||||||
newParseTreeNode.attributes[name] = attr;
|
$tw.utils.addAttributeToParseTreeNode(newParseTreeNode,$tw.utils.extend({},attr,{name: name}));
|
||||||
});
|
});
|
||||||
parseTreeNode = newParseTreeNode;
|
parseTreeNode = newParseTreeNode;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ title: Definition
|
|||||||
|
|
||||||
\whitespace trim
|
\whitespace trim
|
||||||
\function <$codeblock>(code)
|
\function <$codeblock>(code)
|
||||||
<$codeblock code={{{ [<code>addprefix[£]addsuffix[@]] }}}/>
|
<$genesis $type="codeblock" $remappable="no" code={{{ [<code>addprefix[£]addsuffix[@]] }}}/>
|
||||||
\end
|
\end
|
||||||
+
|
+
|
||||||
title: Subject
|
title: Subject
|
||||||
|
@ -24,9 +24,9 @@ title: TiddlerOne
|
|||||||
Whale
|
Whale
|
||||||
</$slot>
|
</$slot>
|
||||||
\end
|
\end
|
||||||
<$transclude $tiddler="TiddlerZero">
|
<$genesis $type="transclude" $remappable="no" $$tiddler="TiddlerZero">
|
||||||
Crocodile
|
Crocodile
|
||||||
</$transclude>
|
</$genesis>
|
||||||
+
|
+
|
||||||
title: ExpectedResult
|
title: ExpectedResult
|
||||||
|
|
||||||
|
@ -15,10 +15,12 @@ title: TiddlerOne
|
|||||||
<!-- Redefine the <$text> widget by defining a transcludable variable with that name -->
|
<!-- Redefine the <$text> widget by defining a transcludable variable with that name -->
|
||||||
\function <$text>(text:'Jaguar')
|
\function <$text>(text:'Jaguar')
|
||||||
\whitespace trim
|
\whitespace trim
|
||||||
<$text text=<<text>>/>
|
<$genesis $type="text" $remappable="no" text=<<text>>/>
|
||||||
<$slot $name="ts-body">
|
<$set name="<$text>" value="">
|
||||||
Whale
|
<$slot $name="ts-body">
|
||||||
</$slot>
|
Whale
|
||||||
|
</$slot>
|
||||||
|
</$set>
|
||||||
\end
|
\end
|
||||||
<$text text="Dingo">
|
<$text text="Dingo">
|
||||||
Crocodile
|
Crocodile
|
||||||
|
@ -6,6 +6,8 @@ tags: [[$:/tags/wiki-test-spec]]
|
|||||||
title: Output
|
title: Output
|
||||||
|
|
||||||
\whitespace trim
|
\whitespace trim
|
||||||
|
<$transclude $tiddler="TiddlerOne" 0="" 1="" 2=""/>
|
||||||
|
|
||||||
{{TiddlerOne}}
|
{{TiddlerOne}}
|
||||||
{{TiddlerOne|Ferret}}
|
{{TiddlerOne|Ferret}}
|
||||||
{{TiddlerOne|Butterfly|Moth}}
|
{{TiddlerOne|Butterfly|Moth}}
|
||||||
@ -17,7 +19,7 @@ title: TiddlerOne
|
|||||||
\whitespace trim
|
\whitespace trim
|
||||||
\parameters(zero:'Jaguar',one:'Lizard',two:'Mole')
|
\parameters(zero:'Jaguar',one:'Lizard',two:'Mole')
|
||||||
<$list filter="[enlist<paramNames>]" counter="counter">
|
<$list filter="[enlist<paramNames>]" counter="counter">
|
||||||
{<$text text={{{ [enlist<paramNames>nth<counter>] }}}/>:<$text text={{{ [enlist<paramValues>nth<counter>] }}}/>}
|
{<$text text={{{ [enlist:raw<paramNames>nth<counter>] }}}/>:<$text text={{{ [enlist:raw<paramValues>nth<counter>] }}}/>}
|
||||||
</$list>
|
</$list>
|
||||||
+
|
+
|
||||||
title: TiddlerTwo
|
title: TiddlerTwo
|
||||||
@ -28,4 +30,4 @@ title: TiddlerTwo
|
|||||||
+
|
+
|
||||||
title: ExpectedResult
|
title: ExpectedResult
|
||||||
|
|
||||||
<p></p><p>{0:Ferret}</p><p>{0:Butterfly}{1:Moth}</p><p>{0:Beetle}{1:Scorpion}{2:Snake}</p><p>({zero:Beetle}{one:Scorpion}{two:Snake})</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>({zero:Beetle}{one:Scorpion}{two:Snake})</p>
|
Loading…
Reference in New Issue
Block a user