/*\ title: js/WikiTextParseTree.js A container for the parse tree generated by parsing wikitext \*/ (function(){ /*jslint node: true */ "use strict"; var WikiTextRenderer = require("./WikiTextRenderer.js").WikiTextRenderer, HTML = require("./HTML.js").HTML, ArgParser = require("./ArgParser.js").ArgParser, utils = require("./Utils.js"); // Intialise the parse tree object var WikiTextParseTree = function(tree,dependencies,store) { this.tree = tree; this.dependencies = dependencies; this.store = store; }; // Compile the parse tree into a JavaScript function that returns the required // representation of the tree WikiTextParseTree.prototype.compile = function(type,treenode) { /*jslint evil: true */ treenode = treenode || this.tree; var renderer = new WikiTextRenderer(), renderStep = {}, renderStepIndex = renderer.addRenderStep(renderStep), output = []; if(type === "text/html") { this.compileSubTreeHtml(output,renderer,treenode); } else if(type === "text/plain") { this.compileSubTreePlain(output,renderer,treenode); } else { return null; } // Create the parse tree for the rendering step function definition var parseTree = this.store.jsParser.createTree( [ { type: "Function", name: null, params: ["tiddler","renderer","store","utils"], // These are the parameters passed to the tiddler function; must match the invocation in WikiStore.renderTiddler() elements: [ { type: "ReturnStatement", value: { type: "FunctionCall", name: { type: "PropertyAccess", base: { type: "ArrayLiteral", elements: output }, name: "join" }, "arguments": [ { type: "StringLiteral", value: "" } ] } } ] } ]); renderStep.type = "main"; renderStep.step = renderStepIndex; renderStep.dependencies = {}; renderStep.handler = parseTree.compile("application/javascript").render; return renderer; }; var pushString = function(output,s) { var last = output[output.length-1]; if(output.length > 0 && last.type === "StringLiterals") { last.value.push(s); } else if (output.length > 0 && last.type === "StringLiteral") { last.type = "StringLiterals"; last.value = [last.value,s]; } else { output.push({type: "StringLiteral", value: s}); } }; WikiTextParseTree.prototype.compileMacroCall = function(output,renderer,type,node) { /*jslint evil: true */ var name = node.name, params = node.params, macro = this.store.macros[name], p, n, renderStep = {}, renderStepIndex = renderer.addRenderStep(renderStep); // Check for errors if(!macro) { pushString(output,"{{** Unknown macro '" + name + "' **}}"); return; } if(macro.types.indexOf(type) === -1) { pushString(output,"{{** Macro '" + name + "' cannot render to MIME type '" + type + "'**}}"); return; } renderStep.type = "macro"; renderStep.macro = name; renderStep.renderType = type; renderStep.step = renderStepIndex; renderStep.dependencies = node.dependencies; // Slot the parameters into the macro call var properties = []; for(p in params) { if(params[p].type === "string") { n = {type: "StringLiteral", value: params[p].value}; } else { n = this.store.jsParser.parse(params[p].value).tree.elements[0]; } properties.push({ type: "PropertyAssignment", name: p, value: n }); } renderStep.params = this.store.jsParser.createTree([ { type: "Function", name: null, params: ["tiddler","renderer","store","utils"], // These are the parameters passed to the tiddler function; must match the invocation in WikiStore.renderTiddler() elements: [ { type: "ReturnStatement", value: { type: "ObjectLiteral", properties: properties } } ] } ]).compile("application/javascript").render; // Compile any child nodes var subOutput = []; if(node.children) { this.compileSubTreeHtml(subOutput,renderer,node.children); } renderStep.content = this.store.jsParser.createTree([ { type: "Function", name: null, params: ["tiddler","renderer","store","utils"], // These are the parameters passed to the tiddler function; must match the invocation in WikiStore.renderTiddler() elements: [ { type: "ReturnStatement", value: { type: "FunctionCall", name: { type: "PropertyAccess", base: { type: "ArrayLiteral", elements: subOutput }, name: "join" }, "arguments": [ { type: "StringLiteral", value: "" } ] } } ] } ]).compile("application/javascript").render; // Add the wrapper node var wrapperTag = macro.wrapperTag || "div"; if(type === "text/html" && !this.store.disableHtmlWrapperNodes) { pushString(output,HTML(HTML.elem(wrapperTag,{ "data-tw-macro": name, "data-tw-render-step": renderStepIndex }))); } // Output the macro call output.push({ type: "FunctionCall", name: { base: { name: "renderer", type: "Variable"}, name: "render", type: "PropertyAccess"}, "arguments": [ { type: "Variable", name: "tiddler" },{ type: "Variable", name: "store" },{ type: "NumericLiteral", value: renderStepIndex }] }); if(type === "text/html" && !this.store.disableHtmlWrapperNodes) { pushString(output,""); } }; WikiTextParseTree.prototype.compileElementHtml = function(output,renderer,element,options) { options = options || {}; pushString(output,HTML(HTML.elem(element.type,element.attributes))); if(!options.selfClosing) { if(element.children) { this.compileSubTreeHtml(output,renderer,element.children); } pushString(output,""); } }; WikiTextParseTree.prototype.compileSubTreeHtml = function(output,renderer,tree) { for(var t=0; t"))], ["treeNode"] )]; }, renderDependencies = function(dependencies) { var output = []; for(var d in dependencies) { if(d === "dependentAll") { output.push(HTML.splitLabel("dependency",[HTML.text(d)],[HTML.text(dependencies[d])])); } else { var dependents = []; for(var t in dependencies[d]) { dependents.push(t); } output.push(HTML.splitLabel("dependency",[HTML.text(d)],[HTML.text(dependents.join(", "))])); } } return HTML.splitLabel( "dependencies", [HTML.text("Dependencies")], output ); }, renderMacroNode = function(node) { var params = [], ret = []; for(var p in node.params) { var v = node.params[p].value; if(node.params[p].type === "eval") { v = "{{" + v + "}}"; } params.push(HTML.splitLabel( "param", [HTML.text(p)], [HTML.text(v)] )); } ret.push(HTML.splitLabel( "macro", [HTML.text(node.name)], params, ["treeNode"] )); if(node.dependencies) { ret.push(renderDependencies(node.dependencies)); } if(node.children) { ret.push(renderArray(node.children)); } return ret; }, renderHtmlNode = function(node) { var attributes = [], ret = []; for(var a in node.attributes) { var v = node.attributes[a]; if(typeof v === "string") { v = v; } else if(v instanceof Array) { v = v.join("; "); } else if(typeof v === "object") { var o = []; for(var n in v) { o.push(n,":",v[n],";"); } v = o.join(""); } attributes.push(HTML.splitLabel( "attribute", [HTML.text(a)], [HTML.text(v)] )); } ret.push(HTML.splitLabel( "html", [HTML.text(node.type)], attributes, ["treeNode"] )); if(node.children) { ret.push(renderArray(node.children)); } return ret; }; renderNode = function(node) { if(node.type === "text") { return renderTextNode(node); } else if(node.type === "macro") { return renderMacroNode(node); } else { return renderHtmlNode(node); } }; return HTML(renderDependencies(this.dependencies),type) + HTML(renderArray(this.tree),type); }; exports.WikiTextParseTree = WikiTextParseTree; })();