From 0439f259b47ec953bc78fcb7407a7be691de03a5 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Thu, 16 Feb 2012 20:38:10 +0000 Subject: [PATCH] Switched over to using new Renderer class --- js/App.js | 8 +- js/HTML.js | 278 ------------------------------ js/ImageParser.js | 6 +- js/JSONParser.js | 14 +- js/Utils.js | 2 +- js/WikiStore.js | 218 +---------------------- js/WikiTextParseTree.js | 370 +--------------------------------------- js/WikiTextParser.js | 4 +- js/WikiTextRenderer.js | 136 --------------- js/WikiTextRules.js | 95 +++++++---- js/macros/echo.js | 10 +- js/macros/image.js | 44 +++-- js/macros/info.js | 10 +- js/macros/link.js | 30 ++-- js/macros/list.js | 32 ++-- js/macros/slider.js | 28 +-- js/macros/story.js | 106 +++++++----- js/macros/tiddler.js | 28 ++- js/macros/version.js | 6 +- js/macros/video.js | 47 +++-- js/macros/view.js | 45 +++-- 21 files changed, 300 insertions(+), 1217 deletions(-) delete mode 100644 js/HTML.js delete mode 100644 js/WikiTextRenderer.js diff --git a/js/App.js b/js/App.js index 3ce39d266..2e8658bab 100644 --- a/js/App.js +++ b/js/App.js @@ -13,6 +13,7 @@ var WikiStore = require("./WikiStore.js").WikiStore, Tiddler = require("./Tiddler.js").Tiddler, tiddlerInput = require("./TiddlerInput.js"), tiddlerOutput = require("./TiddlerOutput.js"), + Renderer = require("./Renderer.js").Renderer, WikiTextParser = require("./WikiTextParser.js").WikiTextParser, JSONParser = require("./JSONParser.js").JSONParser, JavaScriptParser = require("./JavaScriptParser.js").JavaScriptParser, @@ -99,9 +100,8 @@ var App = function() { // Set up navigation if we're in the browser if(this.isBrowser) { // Open the PageTemplate - var div = document.createElement("div"); - this.store.renderTiddlerInNode(div,"PageTemplate"); - document.body.appendChild(div); + var renderer = new Renderer("PageTemplate",null,this.store); + renderer.renderInDom(document.body); // Set up a timer to change the value of a tiddler var me = this; window.setInterval(function() { @@ -112,7 +112,7 @@ var App = function() { },3000); // Register an event handler to handle refreshing the DOM this.store.addEventListener("",function(changes) { - me.store.refreshDomNode(div,changes); + renderer.refreshInDom(changes); }); } }; diff --git a/js/HTML.js b/js/HTML.js deleted file mode 100644 index d4f76300b..000000000 --- a/js/HTML.js +++ /dev/null @@ -1,278 +0,0 @@ -/*\ -title: js/HTML.js - -Represents a fragment of HTML as a JavaScript object tree structure. Helper methods are provided to simplify -constructing HTML trees and to render the tree as an HTML string. - -The nodes in the tree have a `type` field that is the name of the node for HTML elements: - - {type: "br", attributes: {name: "value"}} - -Attributes values can be strings, arrays of strings or hashmaps. String arrays are -rendered by joining them together with a space. Hashmaps are rendered as `attr="name1:value1;name2:value2;"`. - -Elements with child nodes are expressed as: - - {type: "div", children: []} - -Text nodes are represented as: - - {type: "text", value: "A string"} - -HTML entities are represented as: - - {type: "entity", value: "quot"} - -It is sometimes useful to be able to mix raw strings of HTML too: - - {type: "raw", value: "
Something
"} - -Other types of node can also be placed in the tree, but they will be ignored by the built-in render function. -For example, nodes of type `"macro"` are used by the WikiTextParser. - -\*/ -(function(){ - -/*jslint node: true */ -"use strict"; - -var utils = require("./Utils.js"); - -/* -Constructs an HTMLParseTree from a tree of nodes. A single node or an array of nodes can be passed. - -As a shortcut, the constructor can be called as an ordinary function without the new keyword, in which case -it by default returns the `text/html` rendering of the tree. -*/ -var HTML = function(tree,type) { - if(this instanceof HTML) { - // Called as a constructor - this.tree = tree; - } else { - // Called as a function - type = type || "text/html"; - return (new HTML(tree)).render(type); - } -}; - -/* -Static method to simplify constructing an HTML element node - type: element name - attributes: hashmap of element attributes to add - options: hashmap of options -The attributes hashmap can contain strings or hashmaps of strings, (they are processed to attr="name1:value1;name2:value2;") -The options include: - content: a string to include as content in the element (also generates closing tag) - classes: an array of classnames to apply to the element - selfClosing: causes the element to be rendered with a trailing /, as in
- insertAfterAttributes: a string to insert after the attribute section of the element -*/ -HTML.elem = function(type,attributes,children) { - var e = {type: type}; - if(attributes) { - e.attributes = attributes; - } - if(children) { - e.children = children; - } - return e; -}; - -/* -Static method to construct a text node -*/ -HTML.text = function(value) { - return {type: "text", value: value}; -}; - -/* -Static method to construct an entity -*/ -HTML.entity = function(value) { - return {type: "entity", value: value}; -}; - -/* -Static method to construct a raw HTML node -*/ -HTML.raw = function(value) { - return {type: "raw", value: value}; -}; - -/* -Static method to construct a macro call -*/ -HTML.macro = function(name,params,children,dependencies) { - var m = {type: "macro", name: name, params: params, dependencies: dependencies}; - if(children) { - m.children = children; - } - return m; -}; - -/* -Static method to construct a label -*/ -HTML.label = function(type,value,classes) { - classes = (classes || []).slice(0); - classes.push("label"); - return HTML.elem("span",{ - "class": classes, - "data-tw-label-type": type - },value); -}; - -/* -Static method to construct a split label -*/ -HTML.splitLabel = function(type,left,right,classes) { - classes = (classes || []).slice(0); - classes.push("splitLabel"); - return HTML.elem("span",{ - "class": classes - },[ - HTML.elem("span",{ - "class": ["splitLabelLeft"], - "data-tw-label-type": type - },left), - HTML.elem("span",{ - "class": ["splitLabelRight"] - },right) - ]); -}; - -/* -Static method to construct a slider -*/ -HTML.slider = function(type,label,tooltip,body) { - var attributes = { - "class": "tw-slider", - "data-tw-slider-type": type - }; - if(tooltip) { - attributes.alt = tooltip; - attributes.title = tooltip; - } - return HTML.elem("div", - attributes, - [ - HTML.elem("a", - { - "class": ["tw-slider-label"] - },[ - HTML.text(label) - ] - ), - HTML.elem("div", - { - "class": ["tw-slider-body"], - "style": {"display": "none"} - }, - body - ) - ] - ); -}; - -/* -Render the HTML tree to a string, either of "text/html" or "text/plain" -*/ -HTML.prototype.render = function(targetType) { - if(targetType == "text/plain") { - return this.renderPlain().join(""); - } else if(targetType == "text/html") { - return this.renderHtml().join(""); - } else { - return null; - } -}; - -/* -Render the HTML tree to a "text/html" string, returned as a string array -*/ -HTML.prototype.renderHtml = function(output,node) { - output = output || []; - node = node || this.tree; - if(node instanceof Array) { - for(var t=0; t"); - if(node.children) { - this.renderHtml(output,node.children); - output.push(""); - } - break; - } - } - return output; -}; - -/* -Render the HTML tree to a "text/plain" string, returned as a string array -*/ -HTML.prototype.renderPlain = function(output,node) { - output = output || []; - node = node || this.tree; - if(node instanceof Array) { - for(var t=0; t 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; })(); diff --git a/js/WikiTextParser.js b/js/WikiTextParser.js index 4e0d80e7d..450912b64 100644 --- a/js/WikiTextParser.js +++ b/js/WikiTextParser.js @@ -33,7 +33,7 @@ HTML nodes look like this: var WikiTextRules = require("./WikiTextRules.js"), WikiTextParseTree = require("./WikiTextParseTree.js").WikiTextParseTree, - HTML = require("./HTML.js").HTML, + Renderer = require("./Renderer.js").Renderer, utils = require("./Utils.js"), util = require("util"); @@ -97,7 +97,7 @@ WikiTextParser.prototype.mergeDependencies = function(newDependencies) { WikiTextParser.prototype.outputText = function(place,startPos,endPos) { if(startPos < endPos) { - place.push(HTML.text(this.source.substring(startPos,endPos))); + place.push(Renderer.TextNode(this.source.substring(startPos,endPos))); } }; diff --git a/js/WikiTextRenderer.js b/js/WikiTextRenderer.js deleted file mode 100644 index 9d632906f..000000000 --- a/js/WikiTextRenderer.js +++ /dev/null @@ -1,136 +0,0 @@ -/*\ -title: js/WikiTextRenderer.js - -An array of JavaScript functions that generate a specified representation of a parse tree - -\*/ -(function(){ - -/*jslint node: true */ -"use strict"; - -var HTML = require("./HTML.js").HTML, - utils = require("./Utils.js"); - -var WikiTextRenderer = function() { - this.renderSteps = []; // Array of {step: n, renderType: "main"|"macro", dependencies: {},handler: function(tiddler,renderer,store,utils) {}} -}; - -WikiTextRenderer.prototype.addRenderStep = function(renderStep) { - this.renderSteps.push(renderStep); - return this.renderSteps.length - 1; -}; - -WikiTextRenderer.prototype.render = function(tiddler,store,renderStep) { - renderStep = renderStep || 0; - var step = this.renderSteps[renderStep]; - if(renderStep < this.renderSteps.length) { - switch(step.type) { - case "main": - return step.handler(tiddler,this,store,utils); - case "macro": - return store.renderMacro(step.macro, - step.renderType, - tiddler, - step.params(tiddler,this,store,utils), - step.content(tiddler,this,store,utils)); - } - } else { - return null; - } -}; - -WikiTextRenderer.prototype.rerender = function(node,changes,tiddler,store,renderStep) { - renderStep = renderStep || 0; - var step = this.renderSteps[renderStep]; - if(renderStep < this.renderSteps.length) { - switch(step.type) { - case "main": - node.innerHTML = step.handler(tiddler,this,store,utils); - break; - case "macro": - store.rerenderMacro(node,changes,step.macro, - step.renderType, - tiddler, - step.params(tiddler,this,store,utils), - step.content(tiddler,this,store,utils)); - break; - } - } -}; - -WikiTextRenderer.prototype.toString = function(type) { - var renderNode, - renderArray = function(tree) { - var children = []; - for(var t=0; t"))] - )); - } - if(node.dependencies) { - var dependencies = []; - for(var d in node.dependencies) { - if(d === "dependentAll") { - dependencies.push(HTML.splitLabel("dependency",[HTML.text(d)],[HTML.text(node.dependencies[d])])); - } else { - var dependents = []; - for(var t in node.dependencies[d]) { - dependents.push(t); - } - dependencies.push(HTML.splitLabel("dependency",[HTML.text(d)],[HTML.text(dependents.join(","))])); - } - } - ret.push(HTML.splitLabel( - "dependencies", - [HTML.text("Dependencies")], - dependencies - )); - } - if(node.content) { - ret.push(HTML.splitLabel( - "content", - [HTML.text("content")], - [HTML.raw(utils.htmlEncode(node.content.toString()).replace(/\n/g,"
"))] - )); - } - if(node.handler) { - ret.push(HTML.splitLabel( - "handler", - [HTML.text("handler")], - [HTML.raw(utils.htmlEncode(node.handler.toString()).replace(/\n/g,"
"))] - )); - } - return ret; - }; - return HTML(renderArray(this.renderSteps),type); -}; - -exports.WikiTextRenderer = WikiTextRenderer; - -})(); diff --git a/js/WikiTextRules.js b/js/WikiTextRules.js index 7c9df40d1..2152a0051 100755 --- a/js/WikiTextRules.js +++ b/js/WikiTextRules.js @@ -8,7 +8,7 @@ title: js/WikiTextRules.js "use strict"; var ArgParser = require("./ArgParser.js").ArgParser, - HTML = require("./HTML.js").HTML, + Renderer = require("./Renderer.js").Renderer, util = require("util"); var textPrimitives = { @@ -97,11 +97,38 @@ var enclosedTextHelper = function(w) { var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { var text = lookaheadMatch[1]; - w.output.push(HTML.elem(this.element,null,[HTML.text(text)])); + w.output.push(Renderer.ElementNode(this.element,null,[Renderer.TextNode(text)])); w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length; } }; +var compileMacroParams = function(w,params) { + // Slot the parameters into the macro call + var properties = [],n; + for(var p in params) { + if(params[p].type === "string") { + n = {type: "StringLiteral", value: params[p].value}; + } else { + n = w.store.jsParser.parse(params[p].value).tree.elements[0]; + } + properties.push({type: "PropertyAssignment",name: p,value: n}); + } + return w.store.jsParser.createTree([ + { + type: "Function", + name: null, + params: ["tiddler","store","utils"], // These are the parameters passed to the parameter expressions + elements: [ { + type: "ReturnStatement", + value: { + type: "ObjectLiteral", + properties: properties + } + } ] + } + ]).compile("application/javascript").render; +}; + var insertMacroCall = function(w,output,name,params,children) { var macro = w.store.macros[name], dependencies = {}; @@ -131,7 +158,7 @@ var insertMacroCall = function(w,output,name,params,children) { } } w.mergeDependencies(dependencies); - output.push(HTML.macro(name,params,children,dependencies)); + output.push(Renderer.MacroNode(name,compileMacroParams(w,params),children,dependencies,w.store)); } }; @@ -174,7 +201,7 @@ var rules = [ rowTypes: {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"}, handler: function(w) { - var table = HTML.elem("table",{"class": "twtable"},[]); + var table = Renderer.ElementNode("table",{"class": "twtable"},[]); w.output.push(table); var prevColumns = []; var currRowType = null; @@ -190,7 +217,7 @@ var rules = [ w.nextMatch += lookaheadMatch[0].length+1; } else { if(nextRowType != currRowType) { - rowContainer = HTML.elem(this.rowTypes[nextRowType],{},[]); + rowContainer = Renderer.ElementNode(this.rowTypes[nextRowType],{},[]); table.children.push(rowContainer); currRowType = nextRowType; } @@ -205,7 +232,7 @@ var rules = [ rowContainer.attributes.align = rowCount === 0 ? "top" : "bottom"; w.subWikifyTerm(rowContainer.children,this.rowTermRegExp); } else { - var theRow = HTML.elem("tr",{},[]); + var theRow = Renderer.ElementNode("tr",{},[]); theRow.attributes["class"] = rowCount%2 ? "oddRow" : "evenRow"; rowContainer.children.push(theRow); this.rowHandler(w,theRow.children,prevColumns); @@ -261,11 +288,11 @@ var rules = [ } var cell; if(chr == "!") { - cell = HTML.elem("th",{},[]); + cell = Renderer.ElementNode("th",{},[]); e.push(cell); w.nextMatch++; } else { - cell = HTML.elem("td",{},[]); + cell = Renderer.ElementNode("td",{},[]); e.push(cell); } prevCell = cell; @@ -295,7 +322,7 @@ var rules = [ termRegExp: /(\n)/mg, handler: function(w) { - var e = HTML.elem("h" + w.matchLength,{},[]); + var e = Renderer.ElementNode("h" + w.matchLength,{},[]); w.output.push(e); w.subWikifyTerm(e.children,this.termRegExp); } @@ -339,7 +366,7 @@ var rules = [ if(currLevel !== 0 && target.children) { target = target.children[target.children.length-1]; } - e = HTML.elem(listType,{},[]); + e = Renderer.ElementNode(listType,{},[]); target.push(e); stack.push(e.children); } @@ -351,13 +378,13 @@ var rules = [ stack.pop(); } else if(listLevel == currLevel && listType != currType) { stack.pop(); - e = HTML.elem(listType,{},[]); + e = Renderer.ElementNode(listType,{},[]); stack[stack.length-1].push(e); stack.push(e.children); } currLevel = listLevel; currType = listType; - e = HTML.elem(itemType,{},[]); + e = Renderer.ElementNode(itemType,{},[]); stack[stack.length-1].push(e); w.subWikifyTerm(e.children,this.termRegExp); this.lookaheadRegExp.lastIndex = w.nextMatch; @@ -372,7 +399,7 @@ var rules = [ termRegExp: /(^<<<(\n|$))/mg, element: "blockquote", handler: function(w) { - var e = HTML.elem(this.element,{},[]); + var e = Renderer.ElementNode(this.element,{},[]); w.output.push(e); w.subWikifyTerm(e.children,this.termRegExp); } @@ -393,7 +420,7 @@ var rules = [ do { if(newLevel > currLevel) { for(t=currLevel; t\\n?", handler: function(w) { - w.output.push(HTML.elem("hr")); + w.output.push(Renderer.ElementNode("hr")); } }, @@ -492,7 +519,7 @@ var rules = [ } insertMacroCall(w,w.output,"link",{ target: {type: "string", value: link} - },[HTML.text(text)]); + },[Renderer.TextNode(text)]); w.nextMatch = this.lookaheadRegExp.lastIndex; } } @@ -519,7 +546,7 @@ var rules = [ if(w.autoLinkWikiWords) { insertMacroCall(w,w.output,"link",{ target: {type: "string", value: w.matchText} - },[HTML.text(w.source.substring(w.matchStart,w.nextMatch))]); + },[Renderer.TextNode(w.source.substring(w.matchStart,w.nextMatch))]); } else { w.outputText(w.output,w.matchStart,w.nextMatch); } @@ -533,7 +560,7 @@ var rules = [ { insertMacroCall(w,w.output,"link",{ target: {type: "string", value: w.matchText} - },[HTML.text(w.source.substring(w.matchStart,w.nextMatch))]); + },[Renderer.TextNode(w.source.substring(w.matchStart,w.nextMatch))]); } }, @@ -584,7 +611,7 @@ var rules = [ this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { - w.output.push(HTML.elem("html",{},[HTML.raw(lookaheadMatch[1])])); + w.output.push(Renderer.ElementNode("html",{},[Renderer.RawNode(lookaheadMatch[1])])); w.nextMatch = this.lookaheadRegExp.lastIndex; } } @@ -611,32 +638,32 @@ var rules = [ var e,lookaheadRegExp,lookaheadMatch; switch(w.matchText) { case "''": - e = HTML.elem("strong",null,[]); + e = Renderer.ElementNode("strong",null,[]); w.output.push(e); w.subWikifyTerm(e.children,/('')/mg); break; case "//": - e = HTML.elem("em",null,[]); + e = Renderer.ElementNode("em",null,[]); w.output.push(e); w.subWikifyTerm(e.children,/(\/\/)/mg); break; case "__": - e = HTML.elem("u",null,[]); + e = Renderer.ElementNode("u",null,[]); w.output.push(e); w.subWikifyTerm(e.children,/(__)/mg); break; case "^^": - e = HTML.elem("sup",null,[]); + e = Renderer.ElementNode("sup",null,[]); w.output.push(e); w.subWikifyTerm(e.children,/(\^\^)/mg); break; case "~~": - e = HTML.elem("sub",null,[]); + e = Renderer.ElementNode("sub",null,[]); w.output.push(e); w.subWikifyTerm(e.children,/(~~)/mg); break; case "--": - e = HTML.elem("strike",null,[]); + e = Renderer.ElementNode("strike",null,[]); w.output.push(e); w.subWikifyTerm(e.children,/(--)/mg); break; @@ -645,7 +672,7 @@ var rules = [ lookaheadRegExp.lastIndex = w.matchStart; lookaheadMatch = lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { - w.output.push(HTML.elem("code",null,[HTML.text(lookaheadMatch[1])])); + w.output.push(Renderer.ElementNode("code",null,[Renderer.TextNode(lookaheadMatch[1])])); w.nextMatch = lookaheadRegExp.lastIndex; } break; @@ -654,7 +681,7 @@ var rules = [ lookaheadRegExp.lastIndex = w.matchStart; lookaheadMatch = lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { - w.output.push(HTML.elem("code",null,[HTML.text(lookaheadMatch[1])])); + w.output.push(Renderer.ElementNode("code",null,[Renderer.TextNode(lookaheadMatch[1])])); w.nextMatch = lookaheadRegExp.lastIndex; } break; @@ -669,7 +696,7 @@ var rules = [ { switch(w.matchText) { case "@@": - var e = HTML.elem("span",null,[]); + var e = Renderer.ElementNode("span",null,[]); w.output.push(e); var styles = inlineCssHelper(w); if(styles.length === 0) @@ -684,7 +711,7 @@ var rules = [ var lookaheadMatch = lookaheadRegExp.exec(w.source); if(lookaheadMatch) { w.nextMatch = lookaheadRegExp.lastIndex; - e = HTML.elem(lookaheadMatch[2] == "\n" ? "div" : "span",{ + e = Renderer.ElementNode(lookaheadMatch[2] == "\n" ? "div" : "span",{ "class": lookaheadMatch[1] },[]); w.output.push(e); @@ -700,7 +727,7 @@ var rules = [ match: "--", handler: function(w) { - w.output.push(HTML.entity("—")); + w.output.push(Renderer.EntityNode("—")); } }, @@ -709,7 +736,7 @@ var rules = [ match: "\\n|
", handler: function(w) { - w.output.push(HTML.elem("br")); + w.output.push(Renderer.ElementNode("br")); } }, @@ -722,7 +749,7 @@ var rules = [ this.lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = this.lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { - w.output.push(HTML.text(lookaheadMatch[1])); + w.output.push(Renderer.TextNode(lookaheadMatch[1])); w.nextMatch = this.lookaheadRegExp.lastIndex; } } @@ -733,7 +760,7 @@ var rules = [ match: "&#?[a-zA-Z0-9]{2,8};", handler: function(w) { - w.output.push(HTML.entity(w.matchText)); + w.output.push(Renderer.EntityNode(w.matchText)); } } diff --git a/js/macros/echo.js b/js/macros/echo.js index 8417d2110..fac52866e 100644 --- a/js/macros/echo.js +++ b/js/macros/echo.js @@ -7,7 +7,7 @@ title: js/macros/echo.js /*jslint node: true */ "use strict"; -var utils = require("../Utils.js"); +var Renderer = require("../Renderer.js").Renderer; exports.macro = { name: "echo", @@ -15,12 +15,8 @@ exports.macro = { params: { text: {byPos: 0, type: "text", optional: false} }, - render: function(type,tiddler,store,params) { - if(type === "text/html") { - return utils.htmlEncode(params.text); - } else { - return params.text; - } + execute: function(macroNode,tiddler,store) { + return [Renderer.TextNode(macroNode.params.text)]; } }; diff --git a/js/macros/image.js b/js/macros/image.js index ec4522071..4b5bf4cc9 100644 --- a/js/macros/image.js +++ b/js/macros/image.js @@ -7,8 +7,7 @@ title: js/macros/image.js /*jslint node: true */ "use strict"; -var HTML = require("../HTML.js").HTML, - utils = require("../Utils.js"); +var Renderer = require("../Renderer.js").Renderer; exports.macro = { name: "image", @@ -18,28 +17,27 @@ exports.macro = { text: {byName: true, type: "text", optional: true}, alignment: {byName: true, type: "text", optional: true} }, - render: function(type,tiddler,store,params) { - if(type === "text/html") { - if(store.tiddlerExists(params.src)) { - if(params.text) { - return HTML(HTML.elem("div",{ - alt: params.text, - title: params.text - },[ - HTML.raw(store.renderTiddler(type,params.src)) - ])); - } else { - return store.renderTiddler(type,params.src); - } - } else { - return HTML(HTML.elem("img",{ - href: params.src, - alt: params.text, - title: params.text - })); + execute: function(macroNode,tiddler,store) { + if(store.tiddlerExists(macroNode.params.src)) { + var imageTree = store.parseTiddler(macroNode.params.src).tree, + cloneImage = []; + for(var t=0; t"); + var templateTree = store.parseText(templateType,templateText).tree; for(t=0; t"); - output.push(renderer.render(store.getTiddler(tiddlers[t]),store)); - pushTag(""); + var cloneTemplate = []; + for(var c=0; c"); - return output.join(""); + return [Renderer.ElementNode("ul",null,content)]; } } }; diff --git a/js/macros/slider.js b/js/macros/slider.js index 82518a8ca..620857c2d 100644 --- a/js/macros/slider.js +++ b/js/macros/slider.js @@ -7,7 +7,7 @@ title: js/macros/slider.js /*jslint node: true */ "use strict"; -var HTML = require("../HTML.js").HTML, +var Renderer = require("../Renderer.js").Renderer, utils = require("../Utils.js"); exports.macro = { @@ -20,23 +20,25 @@ exports.macro = { tooltip: {byPos: 3, type: "text", optional: true} }, events: { - click: function(event,node,tiddler,store,params) { - var el = node.firstChild.firstChild.nextSibling; + click: function(event,macroNode) { + var el = event.currentTarget.firstChild.firstChild.nextSibling; el.style.display = el.style.display === "block" ? "none" : "block"; event.preventDefault(); return false; } }, - render: function(type,tiddler,store,params) { - if(type === "text/html") { - return HTML(HTML.slider(params.name, - params.label, - params.tooltip, - HTML.raw(store.renderTiddler(type,params.targetTiddler))),type); - } else if(type === "text/plain") { - return store.renderTiddler(type,params.target); - } - return null; + execute: function(macroNode,tiddler,store) { + var target = macroNode.params.targetTiddler, + dependencies = {include: {}}; + dependencies.include[target] = 1; + var content = Renderer.SliderNode(macroNode.params.name, + macroNode.params.label, + macroNode.params.tooltip, + [ + Renderer.MacroNode("tiddler",{target: target},null,dependencies,store) + ]); + content.execute(tiddler); + return [content]; } }; diff --git a/js/macros/story.js b/js/macros/story.js index 4128c1522..aeaaa1627 100644 --- a/js/macros/story.js +++ b/js/macros/story.js @@ -8,6 +8,7 @@ title: js/macros/story.js "use strict"; var Tiddler = require("../Tiddler.js").Tiddler, + Renderer = require("../Renderer.js").Renderer, utils = require("../Utils.js"); // Parse the text of a story tiddler into an array of tiddler titles @@ -23,19 +24,6 @@ var parseStory = function(storyText) { return tiddlers; }; -// Search the children of a node looking for the required tiddler rendering -var searchTiddlerNode = function(node,renderTiddler,renderTemplate) { - while(node !== null) { - if(node.getAttribute && node.getAttribute("data-tw-render-tiddler") === renderTiddler) { - if(!renderTemplate || (renderTemplate && node.getAttribute("data-tw-render-template") == renderTemplate)) { - return node; - } - } - node = node.nextSibling; - } - return null; -}; - exports.macro = { name: "story", types: ["text/html","text/plain"], @@ -44,9 +32,9 @@ exports.macro = { template: {byName: true, type: "tiddler", optional: true} }, events: { - "tw-navigate": function(event,node,tiddler,store,params) { - var storyTiddler = store.getTiddler(params.story); - store.addTiddler(new Tiddler(storyTiddler,{text: event.navigateTo + "\n" + storyTiddler.text})); + "tw-navigate": function(event,macroNode) { + var storyTiddler = macroNode.store.getTiddler(macroNode.params.story); + macroNode.store.addTiddler(new Tiddler(storyTiddler,{text: event.navigateTo + "\n" + storyTiddler.text})); $("html,body").animate({ scrollTop: 0 }, 400); @@ -54,53 +42,77 @@ exports.macro = { return false; } }, - render: function(type,tiddler,store,params) { - var tiddlers = parseStory(store.getTiddlerText(params.story)), - output = []; + execute: function(macroNode,tiddler,store) { + var tiddlers = parseStory(store.getTiddlerText(macroNode.params.story)), + content = []; for(var t=0; t t) { + // First delete the DOM nodes + for(n=t; n targetTiddlers.length) { + for(t=targetTiddlers.length; t"; - case "youtube": - return ""; - case "archiveorg": - return ""; - } - } else if (type === "text/plain") { - return ""; // Not really sure how to render a video into plain text... + execute: function(macroNode,tiddler,store) { + var src = macroNode.params.src, + videoType = macroNode.params.type || "vimeo", + videoWidth = macroNode.params.width || 640, + videoHeight = macroNode.params.height || 360; + switch(videoType) { + case "vimeo": + return [Renderer.ElementNode("iframe",{ + src: "http://player.vimeo.com/video/" + src + "?autoplay=0", + width: videoWidth, + height: videoHeight, + frameborder: 0 + })]; + case "youtube": + return [Renderer.ElementNode("iframe",{ + type: "text/html", + src: "http://www.youtube.com/embed/" + src, + width: videoWidth, + height: videoHeight, + frameborder: 0 + })]; + case "archiveorg": + return [Renderer.ElementNode("iframe",{ + src: "http://www.archive.org/embed/" + src, + width: videoWidth, + height: videoHeight, + frameborder: 0 + })]; + default: + return []; } } }; diff --git a/js/macros/view.js b/js/macros/view.js index 265ea5f3d..b1e3541ff 100644 --- a/js/macros/view.js +++ b/js/macros/view.js @@ -7,7 +7,8 @@ title: js/macros/view.js /*jslint node: true */ "use strict"; -var utils = require("../Utils.js"); +var Renderer = require("../Renderer.js").Renderer, + utils = require("../Utils.js"); exports.macro = { name: "view", @@ -17,28 +18,44 @@ exports.macro = { format: {byPos: 1, type: "text", optional: true}, template: {byPos: 2, type: "text", optional: true} }, - render: function(type,tiddler,store,params) { - var encoder = type === "text/html" ? utils.htmlEncode : function(x) {return x;}; + execute: function(macroNode,tiddler,store) { if(!tiddler) { - return "{{** Missing tiddler **}}"; + return Renderer.TextNode("{{** Missing tiddler **}}"); } else { - var v = tiddler[params.field]; + var v = tiddler[macroNode.params.field], + content, + t, + contentClone = []; if(v !== undefined) { - switch(params.format) { + switch(macroNode.params.format) { case "link": - return store.renderMacro("link",type,tiddler,{target: v},encoder(v)); + var dependencies = {link: {}}; + dependencies.link[v] = 1; + var link = Renderer.MacroNode("link", + {target: v}, + [Renderer.TextNode(v)], + dependencies, + store); + link.execute(tiddler); + return [link]; case "wikified": - if(params.field === "text") { - return store.renderTiddler(type,tiddler.title); + if(macroNode.params.field === "text") { + content = store.parseTiddler(tiddler.title).tree; } else { - return store.renderText("text/x-tiddlywiki",v,type,tiddler.title); + content = store.parseText("text/x-tiddlywiki",v).tree; } - break; + for(t=0; t