diff --git a/boot/boot.js b/boot/boot.js index e300ddc2c..c94579dba 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -78,7 +78,7 @@ $tw.utils.error = function(err) { Check if an object has a property */ $tw.utils.hop = function(object,property) { - return Object.prototype.hasOwnProperty.call(object,property); + return object ? Object.prototype.hasOwnProperty.call(object,property) : false; }; /* diff --git a/core/modules/commands/savetiddlers.js b/core/modules/commands/savetiddlers.js index fff1805b6..d4eab787c 100644 --- a/core/modules/commands/savetiddlers.js +++ b/core/modules/commands/savetiddlers.js @@ -39,8 +39,8 @@ Command.prototype.execute = function() { parser = wiki.parseTiddler(template), tiddlers = wiki.filterTiddlers(filter); $tw.utils.each(tiddlers,function(title) { - var renderTree = new $tw.WikiRenderTree(parser,{wiki: wiki}); - renderTree.execute({tiddlerTitle: title}); + var renderTree = new $tw.WikiRenderTree(parser,{wiki: wiki, context: {tiddlerTitle: title}}); + renderTree.execute(); var text = renderTree.render(type); fs.writeFileSync(path.resolve(pathname,encodeURIComponent(title) + extension),text,"utf8"); }); diff --git a/core/modules/rendertree/renderers/element.js b/core/modules/rendertree/renderers/element.js index ac79e31f7..72b80687c 100644 --- a/core/modules/rendertree/renderers/element.js +++ b/core/modules/rendertree/renderers/element.js @@ -19,7 +19,7 @@ var ElementWidget = function(renderer) { this.renderer = renderer; this.tag = this.renderer.parseTreeNode.tag; this.attributes = this.renderer.attributes; - this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,this.renderer.parseTreeNode.children); + this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children); this.events = this.renderer.parseTreeNode.events; }; @@ -40,22 +40,24 @@ ElementWidget.prototype.refreshInDom = function(changedAttributes,changedTiddler /* Element renderer */ -var ElementRenderer = function(renderTree,renderContext,parseTreeNode) { +var ElementRenderer = function(renderTree,parentRenderer,parseTreeNode) { // Store state information this.renderTree = renderTree; - this.renderContext = renderContext; + this.parentRenderer = parentRenderer; this.parseTreeNode = parseTreeNode; // Initialise widget classes if(!this.widgetClasses) { ElementRenderer.prototype.widgetClasses = $tw.modules.applyMethods("widget"); } + // Get the context tiddler title + this.tiddlerTitle = this.renderTree.getContextVariable(this.parentRenderer,"tiddlerTitle"); // Compute our dependencies this.dependencies = {}; var self = this; $tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) { if(attribute.type === "indirect") { var tr = $tw.utils.parseTextReference(attribute.textReference); - self.dependencies[tr.title ? tr.title : renderContext.tiddlerTitle] = true; + self.dependencies[tr.title ? tr.title : self.tiddlerTitle] = true; } }); // Compute our attributes @@ -86,7 +88,7 @@ ElementRenderer.prototype.computeAttributes = function() { var self = this; $tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) { if(attribute.type === "indirect") { - var value = self.renderTree.wiki.getTextReference(attribute.textReference,"",self.renderContext.tiddlerTitle); + var value = self.renderTree.wiki.getTextReference(attribute.textReference,"",self.tiddlerTitle); if(self.attributes[name] !== value) { self.attributes[name] = value; changedAttributes[name] = true; @@ -221,68 +223,6 @@ ElementRenderer.prototype.refreshInDom = function(changedTiddlers) { } }; -ElementRenderer.prototype.getContextTiddlerTitle = function() { - var context = this.renderContext; - while(context) { - if($tw.utils.hop(context,"tiddlerTitle")) { - return context.tiddlerTitle; - } - context = context.parentContext; - } - return undefined; -}; - -/* -Check for render context recursion by returning true if the members of a proposed new render context are already present in the render context chain -*/ -ElementRenderer.prototype.checkContextRecursion = function(newRenderContext) { - var context = this.renderContext; - while(context) { - var match = true; - for(var member in newRenderContext) { - if($tw.utils.hop(newRenderContext,member)) { - if(newRenderContext[member] && newRenderContext[member] !== context[member]) { - match = false; - } - } - } - if(match) { - return true; - } - context = context.parentContext; - } - return false; -}; - -ElementRenderer.prototype.getContextScopeId = function() { - var guidBits = [], - context = this.renderContext; - while(context) { - $tw.utils.each(context,function(field,name) { - if(name !== "parentContext") { - guidBits.push(name + ":" + field + ";"); - } - }); - guidBits.push("-"); - context = context.parentContext; - } - return guidBits.join(""); -}; - -/* -Find a named macro definition -*/ -ElementRenderer.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; -}; - exports.element = ElementRenderer })(); diff --git a/core/modules/rendertree/renderers/entity.js b/core/modules/rendertree/renderers/entity.js index 038ab37a3..e755aa4c3 100644 --- a/core/modules/rendertree/renderers/entity.js +++ b/core/modules/rendertree/renderers/entity.js @@ -15,10 +15,10 @@ Entity renderer /* Entity renderer */ -var EntityRenderer = function(renderTree,renderContext,parseTreeNode) { +var EntityRenderer = function(renderTree,parentRenderer,parseTreeNode) { // Store state information this.renderTree = renderTree; - this.renderContext = renderContext; + this.parentRenderer = parentRenderer; this.parseTreeNode = parseTreeNode; }; diff --git a/core/modules/rendertree/renderers/macrocall.js b/core/modules/rendertree/renderers/macrocall.js index 44f0ddefa..4e25ab90a 100644 --- a/core/modules/rendertree/renderers/macrocall.js +++ b/core/modules/rendertree/renderers/macrocall.js @@ -15,13 +15,13 @@ Macro call renderer /* Macro call renderer */ -var MacroCallRenderer = function(renderTree,renderContext,parseTreeNode) { +var MacroCallRenderer = function(renderTree,parentRenderer,parseTreeNode) { // Store state information this.renderTree = renderTree; - this.renderContext = renderContext; + this.parentRenderer = parentRenderer; this.parseTreeNode = parseTreeNode; // Find the macro definition - var macro = this.findMacroDefinition(this.parseTreeNode.name); + var macro = this.renderTree.findMacroDefinition(this.parentRenderer,this.parseTreeNode.name); // Insert an error message if we couldn't find the macro var childTree; if(!macro) { @@ -33,21 +33,7 @@ var MacroCallRenderer = function(renderTree,renderContext,parseTreeNode) { 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; + this.children = this.renderTree.createRenderers(this,childTree); }; /* diff --git a/core/modules/rendertree/renderers/macrodef.js b/core/modules/rendertree/renderers/macrodef.js index 7d92c528a..f7336a215 100644 --- a/core/modules/rendertree/renderers/macrodef.js +++ b/core/modules/rendertree/renderers/macrodef.js @@ -15,14 +15,14 @@ Macro definition renderer /* Macro definition renderer */ -var MacroDefRenderer = function(renderTree,renderContext,parseTreeNode) { +var MacroDefRenderer = function(renderTree,parentRenderer,parseTreeNode) { // Store state information this.renderTree = renderTree; - this.renderContext = renderContext; + this.parentRenderer = parentRenderer; this.parseTreeNode = parseTreeNode; - // Save the macro definition into the render context - this.renderContext.macroDefinitions = this.renderContext.macroDefinitions || {}; - this.renderContext.macroDefinitions[this.parseTreeNode.name] = this.parseTreeNode; + // Save the macro definition into the context of the rendertree + this.renderTree.context.macroDefinitions = this.renderTree.context.macroDefinitions || {}; + this.renderTree.context.macroDefinitions[this.parseTreeNode.name] = this.parseTreeNode; }; exports.macrodef = MacroDefRenderer diff --git a/core/modules/rendertree/renderers/raw.js b/core/modules/rendertree/renderers/raw.js index ecf0cb811..00def1e5b 100644 --- a/core/modules/rendertree/renderers/raw.js +++ b/core/modules/rendertree/renderers/raw.js @@ -15,10 +15,10 @@ Raw HTML renderer /* Raw HTML renderer */ -var RawRenderer = function(renderTree,renderContext,parseTreeNode) { +var RawRenderer = function(renderTree,parentRenderer,parseTreeNode) { // Store state information this.renderTree = renderTree; - this.renderContext = renderContext; + this.parentRenderer = parentRenderer; this.parseTreeNode = parseTreeNode; }; diff --git a/core/modules/rendertree/renderers/text.js b/core/modules/rendertree/renderers/text.js index b7e2a13cd..3ac0e8684 100644 --- a/core/modules/rendertree/renderers/text.js +++ b/core/modules/rendertree/renderers/text.js @@ -15,10 +15,10 @@ Text renderer /* Text renderer */ -var TextRenderer = function(renderTree,renderContext,parseTreeNode) { +var TextRenderer = function(renderTree,parentRenderer,parseTreeNode) { // Store state information this.renderTree = renderTree; - this.renderContext = renderContext; + this.parentRenderer = parentRenderer; this.parseTreeNode = parseTreeNode; }; diff --git a/core/modules/rendertree/wikirendertree.js b/core/modules/rendertree/wikirendertree.js index 2977db957..34f07a22a 100644 --- a/core/modules/rendertree/wikirendertree.js +++ b/core/modules/rendertree/wikirendertree.js @@ -14,37 +14,41 @@ Wiki text render tree /* Create a render tree object for a parse tree + parser: reference to the parse tree to be rendered + options: see below +Options include: + wiki: mandatory reference to wiki associated with this render tree + context: optional hashmap of context variables (see below) +Context variables include: + tiddlerTitle: title of the tiddler providing the context + templateTitle: title of the tiddler providing the current template + macroDefinitions: hashmap of macro definitions */ var WikiRenderTree = function(parser,options) { this.parser = parser; this.wiki = options.wiki; + this.context = options.context || {}; // Hashmap of the renderer classes if(!this.rendererClasses) { WikiRenderTree.prototype.rendererClasses = $tw.modules.applyMethods("wikirenderer"); } - }; /* Generate the full render tree for this parse tree - renderContext: see below -An renderContext consists of these fields: - tiddlerTitle: title of the tiddler providing the context - parentContext: reference back to previous context in the stack */ -WikiRenderTree.prototype.execute = function(renderContext) { - renderContext = renderContext || {}; - this.rendererTree = this.createRenderers(renderContext,this.parser.tree); +WikiRenderTree.prototype.execute = function() { + this.rendererTree = this.createRenderers(this,this.parser.tree); }; /* Create an array of renderers for an array of parse tree nodes */ -WikiRenderTree.prototype.createRenderers = function(renderContext,parseTreeNodes) { +WikiRenderTree.prototype.createRenderers = function(parentRenderer,parseTreeNodes) { var rendererNodes = []; if(parseTreeNodes) { for(var t=0; t