mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-27 03:57:21 +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
|
||||
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;
|
||||
// Are we rendering to HTML?
|
||||
if(this.renderOutput === "text/html") {
|
||||
@ -56,6 +58,21 @@ MacroCallWidget.prototype.execute = function() {
|
||||
var parser = this.wiki.parseText(this.parseType,text,
|
||||
{parseAsInline: !this.parseTreeNode.isBlock});
|
||||
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 {
|
||||
// Otherwise, we'll render the text
|
||||
var plainText = this.wiki.renderText("text/plain",this.parseType,text,{parentWidget: this});
|
||||
|
@ -83,52 +83,73 @@ options: see below
|
||||
Options include
|
||||
params: array of {name:, value:} for each parameter
|
||||
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 || {};
|
||||
var actualParams = options.params || [],
|
||||
parentWidget = this.parentWidget;
|
||||
// Check for the variable defined in the parent widget (or an ancestor in the prototype chain)
|
||||
if(parentWidget && name in parentWidget.variables) {
|
||||
var variable = parentWidget.variables[name],
|
||||
value = variable.value;
|
||||
value = variable.value,
|
||||
params = this.resolveVariableParameters(variable.params,actualParams);
|
||||
// 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);
|
||||
return value;
|
||||
return {
|
||||
text: value,
|
||||
params: params
|
||||
};
|
||||
}
|
||||
// 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) {
|
||||
var nextAnonParameter = 0, // Next candidate anonymous parameter in macro call
|
||||
paramInfo, paramValue;
|
||||
// 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;
|
||||
}
|
||||
/*
|
||||
Simplified version of getVariableInfo() that just returns the text
|
||||
*/
|
||||
Widget.prototype.getVariable = function(name,options) {
|
||||
return this.getVariableInfo(name,options).text;
|
||||
};
|
||||
|
||||
Widget.prototype.resolveVariableParameters = function(formalParams,actualParams) {
|
||||
formalParams = formalParams || [];
|
||||
actualParams = actualParams || [];
|
||||
var nextAnonParameter = 0, // Next candidate anonymous parameter in macro call
|
||||
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) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
caption: Macro Definitions
|
||||
created: 20150220181617000
|
||||
modified: 20150221221642000
|
||||
modified: 20171215152754837
|
||||
tags: WikiText
|
||||
title: Macro Definitions in WikiText
|
||||
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.
|
||||
|
||||
@ -35,6 +35,36 @@ eg="""<$set name="address" value="Rabbit Hole Hill">
|
||||
</$set>"""/>
|
||||
</$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
|
||||
|
||||
Macros are available to the tiddler that defines them, plus any tiddlers that it transcludes.
|
||||
|
Loading…
Reference in New Issue
Block a user