1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-20 08:44:52 +00:00
TiddlyWiki5/core/modules/rendertree/renderers/macrocall.js

114 lines
3.5 KiB
JavaScript

/*\
title: $:/core/modules/rendertree/renderers/macrocall.js
type: application/javascript
module-type: wikirenderer
Macro call renderer
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Macro call renderer
*/
var MacroCallRenderer = function(renderTree,renderContext,parseTreeNode) {
// Store state information
this.renderTree = renderTree;
this.renderContext = renderContext;
this.parseTreeNode = parseTreeNode;
// Find the macro definition
var macro = this.findMacroDefinition(this.parseTreeNode.name);
// Insert an error message if we couldn't find the macro
var childTree;
if(!macro) {
childTree = [{type: "text", text: "<<Undefined macro: " + this.parseTreeNode.name + ">>"}];
} else {
// Substitute the macro parameters
var text = this.substituteParameters(macro.text,this.parseTreeNode,macro);
// Parse the text
childTree = this.renderTree.wiki.parseText("text/vnd.tiddlywiki",text,{parseAsInline: !this.parseTreeNode.isBlock}).tree;
}
// Create the renderers for the child nodes
this.children = this.renderTree.createRenderers(this.renderContext,childTree);
};
/*
Find a named macro definition
*/
MacroCallRenderer.prototype.findMacroDefinition = function(name) {
var context = this.renderContext;
while(context) {
if(context.macroDefinitions && context.macroDefinitions[name]) {
return context.macroDefinitions[name];
}
context = context.parentContext;
}
return undefined;
};
/*
Expand the parameters in a block of text
*/
MacroCallRenderer.prototype.substituteParameters = function(text,macroCallParseTreeNode,macroDefinition) {
var nextAnonParameter = 0; // Next candidate anonymous parameter in macro call
// Step through each of the parameters in the macro definition
for(var p=0; p<macroDefinition.params.length; p++) {
// Check if we've got a macro call parameter with the same name
var paramInfo = macroDefinition.params[p],
paramValue = undefined;
for(var m=0; m<macroCallParseTreeNode.params.length; m++) {
if(macroCallParseTreeNode.params[m].name === paramInfo.name) {
paramValue = macroCallParseTreeNode.params[m].value;
}
}
// If not, use the next available anonymous macro call parameter
if(!paramValue && macroCallParseTreeNode.params.length > 0) {
while(macroCallParseTreeNode.params[nextAnonParameter].name && nextAnonParameter < macroCallParseTreeNode.params.length-1) {
nextAnonParameter++;
}
if(!macroCallParseTreeNode.params[nextAnonParameter].name) {
paramValue = macroCallParseTreeNode.params[nextAnonParameter].value;
nextAnonParameter++;
}
}
// If we've still not got a value, use the default, if any
paramValue = paramValue || paramInfo["default"] || "";
// Replace any instances of this parameter
text = text.replace(new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue);
}
return text;
};
MacroCallRenderer.prototype.render = function(type) {
var output = [];
$tw.utils.each(this.children,function(node) {
if(node.render) {
output.push(node.render(type));
}
});
return output.join("");
};
MacroCallRenderer.prototype.renderInDom = function() {
// Create the element
this.domNode = document.createElement(this.parseTreeNode.isBlock ? "div" : "span");
this.domNode.setAttribute("data-macro-name",this.parseTreeNode.name);
// Render any child nodes
var self = this;
$tw.utils.each(this.children,function(node,index) {
if(node.renderInDom) {
self.domNode.appendChild(node.renderInDom());
}
});
// Return the dom node
return this.domNode;
};
exports.macrocall = MacroCallRenderer
})();