mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-06-25 06:43:15 +00:00
Make macro parameters available as variables in wikified macros (#3063)
First commit
This commit is contained in:
parent
d2ff164c07
commit
c83231871d
|
@ -48,7 +48,9 @@ MacroCallWidget.prototype.execute = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Get the macro value
|
// Get the macro value
|
||||||
var text = this.getVariable(this.parseTreeNode.name || this.getAttribute("$name"),{params: params}),
|
var macroName = this.parseTreeNode.name || this.getAttribute("$name"),
|
||||||
|
variableInfo = this.getVariableInfo(macroName,{params: params}),
|
||||||
|
text = variableInfo.text,
|
||||||
parseTreeNodes;
|
parseTreeNodes;
|
||||||
// Are we rendering to HTML?
|
// Are we rendering to HTML?
|
||||||
if(this.renderOutput === "text/html") {
|
if(this.renderOutput === "text/html") {
|
||||||
|
@ -56,6 +58,21 @@ MacroCallWidget.prototype.execute = function() {
|
||||||
var parser = this.wiki.parseText(this.parseType,text,
|
var parser = this.wiki.parseText(this.parseType,text,
|
||||||
{parseAsInline: !this.parseTreeNode.isBlock});
|
{parseAsInline: !this.parseTreeNode.isBlock});
|
||||||
parseTreeNodes = parser ? parser.tree : [];
|
parseTreeNodes = parser ? parser.tree : [];
|
||||||
|
// Wrap the parse tree in a vars widget assigning the parameters to variables named "__paramname__"
|
||||||
|
var attributes = {};
|
||||||
|
$tw.utils.each(variableInfo.params,function(param) {
|
||||||
|
var name = "__" + param.name + "__";
|
||||||
|
attributes[name] = {
|
||||||
|
name: name,
|
||||||
|
type: "string",
|
||||||
|
value: param.value
|
||||||
|
};
|
||||||
|
});
|
||||||
|
parseTreeNodes = [{
|
||||||
|
type: "vars",
|
||||||
|
attributes: attributes,
|
||||||
|
children: parseTreeNodes
|
||||||
|
}];
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, we'll render the text
|
// Otherwise, we'll render the text
|
||||||
var plainText = this.wiki.renderText("text/plain",this.parseType,text,{parentWidget: this});
|
var plainText = this.wiki.renderText("text/plain",this.parseType,text,{parentWidget: this});
|
||||||
|
|
|
@ -83,52 +83,73 @@ options: see below
|
||||||
Options include
|
Options include
|
||||||
params: array of {name:, value:} for each parameter
|
params: array of {name:, value:} for each parameter
|
||||||
defaultValue: default value if the variable is not defined
|
defaultValue: default value if the variable is not defined
|
||||||
|
|
||||||
|
Returns an object with the following fields:
|
||||||
|
|
||||||
|
params: array of {name:,value:} of parameters passed to wikitext variables
|
||||||
|
text: text of variable, with parameters properly substituted
|
||||||
*/
|
*/
|
||||||
Widget.prototype.getVariable = function(name,options) {
|
Widget.prototype.getVariableInfo = function(name,options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var actualParams = options.params || [],
|
var actualParams = options.params || [],
|
||||||
parentWidget = this.parentWidget;
|
parentWidget = this.parentWidget;
|
||||||
// Check for the variable defined in the parent widget (or an ancestor in the prototype chain)
|
// Check for the variable defined in the parent widget (or an ancestor in the prototype chain)
|
||||||
if(parentWidget && name in parentWidget.variables) {
|
if(parentWidget && name in parentWidget.variables) {
|
||||||
var variable = parentWidget.variables[name],
|
var variable = parentWidget.variables[name],
|
||||||
value = variable.value;
|
value = variable.value,
|
||||||
|
params = this.resolveVariableParameters(variable.params,actualParams);
|
||||||
// Substitute any parameters specified in the definition
|
// Substitute any parameters specified in the definition
|
||||||
value = this.substituteVariableParameters(value,variable.params,actualParams);
|
$tw.utils.each(params,function(param) {
|
||||||
|
value = $tw.utils.replaceString(value,new RegExp("\\$" + $tw.utils.escapeRegExp(param.name) + "\\$","mg"),param.value);
|
||||||
|
});
|
||||||
value = this.substituteVariableReferences(value);
|
value = this.substituteVariableReferences(value);
|
||||||
return value;
|
return {
|
||||||
|
text: value,
|
||||||
|
params: params
|
||||||
|
};
|
||||||
}
|
}
|
||||||
// If the variable doesn't exist in the parent widget then look for a macro module
|
// If the variable doesn't exist in the parent widget then look for a macro module
|
||||||
return this.evaluateMacroModule(name,actualParams,options.defaultValue);
|
return {
|
||||||
|
text: this.evaluateMacroModule(name,actualParams,options.defaultValue)
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Widget.prototype.substituteVariableParameters = function(text,formalParams,actualParams) {
|
/*
|
||||||
if(formalParams) {
|
Simplified version of getVariableInfo() that just returns the text
|
||||||
var nextAnonParameter = 0, // Next candidate anonymous parameter in macro call
|
*/
|
||||||
paramInfo, paramValue;
|
Widget.prototype.getVariable = function(name,options) {
|
||||||
// Step through each of the parameters in the macro definition
|
return this.getVariableInfo(name,options).text;
|
||||||
for(var p=0; p<formalParams.length; p++) {
|
};
|
||||||
// Check if we've got a macro call parameter with the same name
|
|
||||||
paramInfo = formalParams[p];
|
Widget.prototype.resolveVariableParameters = function(formalParams,actualParams) {
|
||||||
paramValue = undefined;
|
formalParams = formalParams || [];
|
||||||
for(var m=0; m<actualParams.length; m++) {
|
actualParams = actualParams || [];
|
||||||
if(actualParams[m].name === paramInfo.name) {
|
var nextAnonParameter = 0, // Next candidate anonymous parameter in macro call
|
||||||
paramValue = actualParams[m].value;
|
paramInfo, paramValue,
|
||||||
}
|
results = [];
|
||||||
|
// Step through each of the parameters in the macro definition
|
||||||
|
for(var p=0; p<formalParams.length; p++) {
|
||||||
|
// Check if we've got a macro call parameter with the same name
|
||||||
|
paramInfo = formalParams[p];
|
||||||
|
paramValue = undefined;
|
||||||
|
for(var m=0; m<actualParams.length; m++) {
|
||||||
|
if(actualParams[m].name === paramInfo.name) {
|
||||||
|
paramValue = actualParams[m].value;
|
||||||
}
|
}
|
||||||
// If not, use the next available anonymous macro call parameter
|
|
||||||
while(nextAnonParameter < actualParams.length && actualParams[nextAnonParameter].name) {
|
|
||||||
nextAnonParameter++;
|
|
||||||
}
|
|
||||||
if(paramValue === undefined && nextAnonParameter < actualParams.length) {
|
|
||||||
paramValue = actualParams[nextAnonParameter++].value;
|
|
||||||
}
|
|
||||||
// If we've still not got a value, use the default, if any
|
|
||||||
paramValue = paramValue || paramInfo["default"] || "";
|
|
||||||
// Replace any instances of this parameter
|
|
||||||
text = $tw.utils.replaceString(text,new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue);
|
|
||||||
}
|
}
|
||||||
|
// If not, use the next available anonymous macro call parameter
|
||||||
|
while(nextAnonParameter < actualParams.length && actualParams[nextAnonParameter].name) {
|
||||||
|
nextAnonParameter++;
|
||||||
|
}
|
||||||
|
if(paramValue === undefined && nextAnonParameter < actualParams.length) {
|
||||||
|
paramValue = actualParams[nextAnonParameter++].value;
|
||||||
|
}
|
||||||
|
// If we've still not got a value, use the default, if any
|
||||||
|
paramValue = paramValue || paramInfo["default"] || "";
|
||||||
|
// Store the parameter name and value
|
||||||
|
results.push({name: paramInfo.name, value: paramValue});
|
||||||
}
|
}
|
||||||
return text;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
Widget.prototype.substituteVariableReferences = function(text) {
|
Widget.prototype.substituteVariableReferences = function(text) {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
caption: Macro Definitions
|
||||||
created: 20150220181617000
|
created: 20150220181617000
|
||||||
modified: 20150221221642000
|
modified: 20171215152754837
|
||||||
tags: WikiText
|
tags: WikiText
|
||||||
title: Macro Definitions in WikiText
|
title: Macro Definitions in WikiText
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
caption: Macro Definitions
|
|
||||||
|
|
||||||
A [[macro|Macros]] is defined using a `\define` [[pragma|Pragma]]. Like any pragma, this can only appear at the start of a tiddler.
|
A [[macro|Macros]] is defined using a `\define` [[pragma|Pragma]]. Like any pragma, this can only appear at the start of a tiddler.
|
||||||
|
|
||||||
|
@ -35,6 +35,36 @@ eg="""<$set name="address" value="Rabbit Hole Hill">
|
||||||
</$set>"""/>
|
</$set>"""/>
|
||||||
</$importvariables>
|
</$importvariables>
|
||||||
|
|
||||||
|
!! Parameters as Variables
|
||||||
|
|
||||||
|
The parameters to a wikitext macro are also available as special variables named as the parameter name wrapped in double underscores. For example, the example above could also be expressed as:
|
||||||
|
|
||||||
|
```
|
||||||
|
\define sayhi(name:"Bugs Bunny") Hi, I'm <$text text=<<__name__>>/>.
|
||||||
|
```
|
||||||
|
|
||||||
|
Accessing parameters as variables only works in macros that are wikified and not, for example, when a macro is used as an attribute value. The advantage of the technique is that it avoids the parameter value being substituted into the macro as a literal string, which in turn can help avoid issues with parameters that contain quotes.
|
||||||
|
|
||||||
|
For example, consider this macro. It is intended to wrap a DIV around another macro invocation, passing through the single parameter to the inner macro:
|
||||||
|
|
||||||
|
```
|
||||||
|
\define related-tags(base-tag)
|
||||||
|
<div class="wrapper">
|
||||||
|
<$macrocall $name="anothermacro" param="""$base-tag$"""/>
|
||||||
|
</div>
|
||||||
|
\end
|
||||||
|
```
|
||||||
|
|
||||||
|
The code above will fail if the macro is invoked with the argument containing triple double quotes (for example `<<related-tags 'Triple """ Quotes'>>`). Using parameter variables offers a workaround:
|
||||||
|
|
||||||
|
```
|
||||||
|
\define related-tags(base-tag)
|
||||||
|
<div class="wrapper">
|
||||||
|
<$macrocall $name="anothermacro" param=<<__base-tag__>>/>
|
||||||
|
</div>
|
||||||
|
\end
|
||||||
|
```
|
||||||
|
|
||||||
!! Scope
|
!! Scope
|
||||||
|
|
||||||
Macros are available to the tiddler that defines them, plus any tiddlers that it transcludes.
|
Macros are available to the tiddler that defines them, plus any tiddlers that it transcludes.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user