1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-07-08 04:54:23 +00:00
TiddlyWiki5/core/modules/rendertree/renderers/macrocall.js
Jeremy Ruston 6ccf13e624 Widgets and macro calls should be spans not divs
Although it does mean that we'll end up creating divs inside spans,
which isn't strictly legal but works in all browsers
2012-12-20 10:37:51 +00:00

102 lines
3.3 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,childTree;
if($tw.utils.hop(this.renderTree.parser.macroDefinitions,this.parseTreeNode.name)) {
macro = this.renderTree.parser.macroDefinitions[this.parseTreeNode.name];
}
// Insert an error message if we couldn't find the macro
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.new_parseText("text/vnd.tiddlywiki",text).tree;
}
// Create the renderers for the child nodes
this.children = this.renderTree.createRenderers(this.renderContext,childTree);
};
/*
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("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
})();