Refactor rendertree to simplify context handling

Get rid of the separate renderContext stack and instead have a parent
pointer on renderer nodes. This lets us walk back up the render tree to
resolve context references
This commit is contained in:
Jeremy Ruston 2013-05-15 17:32:17 +01:00
parent 32dc09d8ac
commit 8564602256
42 changed files with 175 additions and 183 deletions

View File

@ -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;
};
/*

View File

@ -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");
});

View File

@ -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
})();

View File

@ -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;
};

View File

@ -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);
};
/*

View File

@ -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

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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<parseTreeNodes.length; t++) {
rendererNodes.push(this.createRenderer(renderContext,parseTreeNodes[t]));
rendererNodes.push(this.createRenderer(parentRenderer,parseTreeNodes[t]));
}
}
return rendererNodes;
@ -53,9 +57,9 @@ WikiRenderTree.prototype.createRenderers = function(renderContext,parseTreeNodes
/*
Create a renderer node for a parse tree node
*/
WikiRenderTree.prototype.createRenderer = function(renderContext,parseTreeNode) {
WikiRenderTree.prototype.createRenderer = function(parentRenderer,parseTreeNode) {
var RenderNodeClass = this.rendererClasses[parseTreeNode.type];
return new RenderNodeClass(this,renderContext,parseTreeNode);
return new RenderNodeClass(this,parentRenderer,parseTreeNode);
};
/*
@ -94,6 +98,72 @@ WikiRenderTree.prototype.refreshInDom = function(changes) {
});
};
/*
Find the value of a given context variable for a particular renderer node
*/
WikiRenderTree.prototype.getContextVariable = function(renderer,name) {
while(renderer) {
if($tw.utils.hop(renderer.context,name)) {
return renderer.context[name];
}
renderer = renderer.parentRenderer;
};
return undefined;
};
/*
Check for render context recursion from a particular renderer node by returning true if the members of a proposed new render context are already present in the render context chain
*/
WikiRenderTree.prototype.checkContextRecursion = function(renderer,newContext) {
while(renderer) {
var context = renderer.context;
if(context) {
var match = true;
for(var member in newContext) {
if($tw.utils.hop(context,member)) {
if(newContext[member] !== context[member]) {
match = false;
}
} else {
match = false;
}
}
if(match) {
return true;
}
}
renderer = renderer.parentRenderer;
}
return false;
};
WikiRenderTree.prototype.getContextScopeId = function(renderer) {
var guidBits = [];
while(renderer) {
if(renderer.context) {
$tw.utils.each(renderer.context,function(field,name) {
guidBits.push(name + ":" + field + ";");
});
guidBits.push("-");
}
renderer = renderer.parentRenderer;
}
return guidBits.join("");
};
/*
Find a named macro definition
*/
WikiRenderTree.prototype.findMacroDefinition = function(renderer,name) {
while(renderer) {
if(renderer.context && renderer.context.macroDefinitions && renderer.context.macroDefinitions[name]) {
return renderer.context.macroDefinitions[name];
}
renderer = renderer.parentRenderer;
}
return undefined;
};
exports.WikiRenderTree = WikiRenderTree;
})();

View File

@ -112,8 +112,8 @@ exports.startup = function() {
// Display the PageTemplate
var templateTitle = "$:/templates/PageTemplate",
parser = $tw.wiki.parseTiddler(templateTitle),
renderTree = new $tw.WikiRenderTree(parser,{wiki: $tw.wiki});
renderTree.execute({tiddlerTitle: templateTitle});
renderTree = new $tw.WikiRenderTree(parser,{wiki: $tw.wiki, context: {tiddlerTitle: templateTitle}});
renderTree.execute();
var container = document.createElement("div");
document.body.insertBefore(container,document.body.firstChild);
renderTree.renderInDom(container);

View File

@ -66,16 +66,16 @@ Modal.prototype.display = function(title,options) {
titleText = title;
}
var headerParser = this.wiki.parseText("text/vnd.tiddlywiki-run",titleText,{parseAsInline: true}),
headerRenderTree = new $tw.WikiRenderTree(headerParser,{wiki: $tw.wiki});
headerRenderTree.execute({tiddlerTitle: title});
headerRenderTree = new $tw.WikiRenderTree(headerParser,{wiki: $tw.wiki, context: {tiddlerTitle: title}});
headerRenderTree.execute();
headerRenderTree.renderInDom(headerTitle);
this.wiki.addEventListener("change",function(changes) {
headerRenderTree.refreshInDom(changes);
});
// Render the body of the message
var bodyParser = this.wiki.parseTiddler(title),
bodyRenderTree = new $tw.WikiRenderTree(bodyParser,{wiki: $tw.wiki});
bodyRenderTree.execute({tiddlerTitle: title});
bodyRenderTree = new $tw.WikiRenderTree(bodyParser,{wiki: $tw.wiki, context: {tiddlerTitle: title}});
bodyRenderTree.execute();
bodyRenderTree.renderInDom(modalBody);
this.wiki.addEventListener("change",function(changes) {
bodyRenderTree.refreshInDom(changes);
@ -102,8 +102,8 @@ Modal.prototype.display = function(title,options) {
footerText = '<$button message="tw-close-tiddler" class="btn btn-primary">Close</$button>';
}
var footerParser = this.wiki.parseText("text/vnd.tiddlywiki-run",footerText,{parseAsInline: true}),
footerRenderTree = new $tw.WikiRenderTree(footerParser,{wiki: $tw.wiki});
footerRenderTree.execute({tiddlerTitle: title});
footerRenderTree = new $tw.WikiRenderTree(footerParser,{wiki: $tw.wiki, context: {tiddlerTitle: title}});
footerRenderTree.execute();
footerRenderTree.renderInDom(modalFooterButtons);
this.wiki.addEventListener("change",function(changes) {
footerRenderTree.refreshInDom(changes);

View File

@ -36,8 +36,8 @@ Notifier.prototype.display = function(title,options) {
$tw.utils.addClass(notification,"tw-notification");
// Render the body of the notification
var bodyParser = this.wiki.parseTiddler(title),
bodyRenderTree = new $tw.WikiRenderTree(bodyParser,{wiki: $tw.wiki});
bodyRenderTree.execute({tiddlerTitle: title});
bodyRenderTree = new $tw.WikiRenderTree(bodyParser,{wiki: $tw.wiki, context: {tiddlerTitle: title}});
bodyRenderTree.execute();
bodyRenderTree.renderInDom(notification);
this.wiki.addEventListener("change",function(changes) {
bodyRenderTree.refreshInDom(changes);

View File

@ -35,8 +35,8 @@ StylesheetManager.prototype.addStylesheet = function(title) {
this.stylesheets[title] = true;
// Parse the tiddler and render as plain text
var parser = this.wiki.parseTiddler(title),
renderTree = new $tw.WikiRenderTree(parser,{wiki: this.wiki});
renderTree.execute({tiddlerTitle: title});
renderTree = new $tw.WikiRenderTree(parser,{wiki: this.wiki, context: {tiddlerTitle: title}});
renderTree.execute();
var text = renderTree.render("text/plain");
// Create a style element and put it in the document
var styleNode = document.createElement("style");

View File

@ -48,21 +48,21 @@ ButtonWidget.prototype.generate = function() {
// Set the return element
this.tag = "button";
this.attributes ={"class": classes.join(" ")};
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 = events;
};
ButtonWidget.prototype.dispatchMessage = function(event) {
$tw.utils.dispatchCustomEvent(event.target,this.message,{
param: this.param,
tiddlerTitle: this.renderer.getContextTiddlerTitle()
tiddlerTitle: this.renderer.tiddlerTitle
});
};
ButtonWidget.prototype.triggerPopup = function(event) {
var title = this.popup;
if(this.qualifyTiddlerTitles) {
title = title + "-" + this.renderer.getContextScopeId();
title = title + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
}
$tw.popup.triggerPopup({
domNode: this.renderer.domNode,
@ -74,7 +74,7 @@ ButtonWidget.prototype.triggerPopup = function(event) {
ButtonWidget.prototype.isSelected = function() {
var title = this.set;
if(this.qualifyTiddlerTitles) {
title = title + "-" + this.renderer.getContextScopeId();
title = title + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
}
var tiddler = this.renderer.renderTree.wiki.getTiddler(title);
return tiddler ? tiddler.fields.text === this.setTo : false;
@ -83,7 +83,7 @@ ButtonWidget.prototype.isSelected = function() {
ButtonWidget.prototype.setTiddler = function() {
var title = this.set;
if(this.qualifyTiddlerTitles) {
title = title + "-" + this.renderer.getContextScopeId();
title = title + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
}
var tiddler = this.renderer.renderTree.wiki.getTiddler(title);
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: title, text: this.setTo}));
@ -120,7 +120,7 @@ ButtonWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers
var setTitle = this.set,
popupTitle = this.popup;
if(this.qualifyTiddlerTitles) {
var scopeId = this.renderer.getContextScopeId();
var scopeId = this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
if(setTitle) {
setTitle = setTitle + "-" + scopeId;
}

View File

@ -31,7 +31,7 @@ var CheckboxWidget = function(renderer) {
CheckboxWidget.prototype.generate = function() {
// Get the parameters from the attributes
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.getContextTiddlerTitle());
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
this.tagName = this.renderer.getAttribute("tag");
this["class"] = this.renderer.getAttribute("class");
// Compute classes
@ -59,7 +59,7 @@ CheckboxWidget.prototype.generate = function() {
// Set the return element
this.tag = "label";
this.attributes ={"class": classes.join(" ")};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[nodeCheckbox,nodeSpan]);
this.children = this.renderer.renderTree.createRenderers(this.renderer,[nodeCheckbox,nodeSpan]);
this.events = [{name: "change", handlerObject: this, handlerMethod: "handleChangeEvent"}];
};

View File

@ -26,7 +26,7 @@ var EditWidget = function(renderer) {
EditWidget.prototype.generate = function() {
// Get parameters from our attributes
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.getContextTiddlerTitle());
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
this.fieldName = this.renderer.getAttribute("field","text");
// Choose the editor to use
// TODO: Tiddler field modules should be able to specify a field type from which the editor is derived

View File

@ -88,7 +88,7 @@ TextEditor.prototype.render = function() {
this.editWidget.attributes.style = this.editWidget.attributes.style || "";
this.editWidget.attributes.style += this.editWidget.renderer.parseTreeNode.attributes.style.value;
}
this.editWidget.children = this.editWidget.renderer.renderTree.createRenderers(this.editWidget.renderer.renderContext,[node]);
this.editWidget.children = this.editWidget.renderer.renderTree.createRenderers(this.editWidget.renderer,[node]);
this.editWidget.events = [
{name: "focus", handlerObject: this},
{name: "blur", handlerObject: this},

View File

@ -40,7 +40,7 @@ EncryptWidget.prototype.generate = function() {
// Set the return element
this.tag = "pre";
this.attributes ={"class": "tw-encrypt"};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
type: "text",
text: encryptedText
}]);

View File

@ -26,7 +26,7 @@ ErrorWidget.prototype.generate = function() {
this.attributes = {
"class": "tw-error-widget"
};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
type: "text",
text: this.errorMessage
}]);

View File

@ -21,7 +21,7 @@ var FieldGridWidget = function(renderer) {
FieldGridWidget.prototype.generate = function() {
// Get attributes
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.getContextTiddlerTitle());
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
this.exclude = this.renderer.getAttribute("exclude");
this["class"] = this.renderer.getAttribute("class");
// Set up the exclusion array
@ -73,7 +73,7 @@ FieldGridWidget.prototype.generate = function() {
// Return the table element
this.tag = "table";
this.attributes ={"class": classes.join(" ")};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
type: "element",
tag: "tbody",
children: rows

View File

@ -21,7 +21,7 @@ var FieldsWidget = function(renderer) {
FieldsWidget.prototype.generate = function() {
// Get parameters from our attributes
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.getContextTiddlerTitle());
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
this.template = this.renderer.getAttribute("template");
this.exclude = this.renderer.getAttribute("exclude");
this.stripTitlePrefix = this.renderer.getAttribute("stripTitlePrefix","no") === "yes";
@ -75,7 +75,7 @@ FieldsWidget.prototype.generate = function() {
this.attributes.title = this.renderer.getAttribute("tooltip");
}
// Create the renderers for the wrapper and the children
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
type: "text",
text: text.join("")
}]);

View File

@ -60,7 +60,7 @@ ImportWidget.prototype.generate = function() {
this.attributes = {
"class": classes.join(" ")
};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[fileInput,container]);
this.children = this.renderer.renderTree.createRenderers(this.renderer,[fileInput,container]);
};
ImportWidget.prototype.handleChangeEvent = function(event) {

View File

@ -25,7 +25,7 @@ InfoWidget.types = {
InfoWidget.prototype.generate = function() {
// Get attributes
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.getContextTiddlerTitle());
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.tiddlerTitle);
this.type = this.renderer.getAttribute("type","changecount");
// Get the appropriate value for the current tiddler
var value = "",
@ -39,7 +39,7 @@ InfoWidget.prototype.generate = function() {
// Set the element
this.tag = "span";
this.attributes = {};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
type: "text",
text: value
}]);

View File

@ -31,7 +31,7 @@ LinkWidget.prototype.generate = function() {
this.qualifyHoverTitles = this.renderer.getAttribute("qualifyHoverTitles");
// Qualify the hover tiddler title if needed
if(this.qualifyHoverTitles) {
this.hover = this.hover + "-" + this.renderer.getContextScopeId();
this.hover = this.hover + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
}
// Determine the default link characteristics
this.isExternal = isLinkExternal(this.to);
@ -66,7 +66,7 @@ LinkWidget.prototype.generate = function() {
events.push({name: "mouseout", handlerObject: this, handlerMethod: "handleMouseOverOrOutEvent"});
}
// Get the value of the tw-wikilinks configuration macro
var wikiLinksMacro = this.renderer.findMacroDefinition("tw-wikilinks"),
var wikiLinksMacro = this.renderer.renderTree.findMacroDefinition(this.renderer.parentRenderer,"tw-wikilinks"),
useWikiLinks = wikiLinksMacro ? !(wikiLinksMacro.text.trim() === "no") : true;
// Set up the element
if(useWikiLinks) {
@ -77,7 +77,7 @@ LinkWidget.prototype.generate = function() {
if(this.isExternal) {
this.attributes.href = this.to;
} else {
var wikiLinkTemplateMacro = this.renderer.findMacroDefinition("tw-wikilink-template"),
var wikiLinkTemplateMacro = this.renderer.renderTree.findMacroDefinition(this.renderer.parentRenderer,"tw-wikilink-template"),
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.text.trim() : "$uri_encoded$";
this.wikiLinkText = wikiLinkTemplate.replace("$uri_encoded$",encodeURIComponent(this.to));
this.wikiLinkText = this.wikiLinkText.replace("$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
@ -87,7 +87,7 @@ LinkWidget.prototype.generate = function() {
} else {
this.tag = "span";
}
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);
};
LinkWidget.prototype.handleClickEvent = function(event) {

View File

@ -29,7 +29,7 @@ LinkCatcherWidget.prototype.generate = function() {
this.attributes = {
"class": "tw-linkcatcher"
};
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 = [
{name: "tw-navigate", handlerObject: this, handlerMethod: "handleNavigateEvent"}
];
@ -47,7 +47,7 @@ LinkCatcherWidget.prototype.refreshInDom = function(changedAttributes,changedTid
// Navigate to a specified tiddler
LinkCatcherWidget.prototype.handleNavigateEvent = function(event) {
if(this.to) {
this.renderer.renderTree.wiki.setTextReference(this.to,event.navigateTo,this.renderer.getContextTiddlerTitle());
this.renderer.renderTree.wiki.setTextReference(this.to,event.navigateTo,this.renderer.tiddlerTitle);
}
event.stopPropagation();
return false;

View File

@ -59,7 +59,7 @@ ListWidget.prototype.generate = function() {
this.attributes = {
"class": "tw-list-frame"
};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,listMembers);
this.children = this.renderer.renderTree.createRenderers(this.renderer,listMembers);
};
ListWidget.prototype.getTiddlerList = function() {
@ -72,7 +72,7 @@ ListWidget.prototype.getTiddlerList = function() {
if(!filter) {
filter = "[!is[system]]";
}
this.list = this.renderer.renderTree.wiki.filterTiddlers(filter,this.renderer.getContextTiddlerTitle());
this.list = this.renderer.renderTree.wiki.filterTiddlers(filter,this.renderer.tiddlerTitle);
};
/*
@ -253,7 +253,7 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
this.removeListElement(t);
}
// Insert the empty message
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[this.getEmptyMessage()]);
this.children = this.renderer.renderTree.createRenderers(this.renderer,[this.getEmptyMessage()]);
$tw.utils.each(this.children,function(node) {
if(node.renderInDom) {
self.renderer.domNode.appendChild(node.renderInDom());
@ -273,7 +273,7 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
var index = this.findListElementByTitle(t,this.list[t]);
if(index === undefined) {
// The list element isn't there, so we need to insert it
this.children.splice(t,0,this.renderer.renderTree.createRenderer(this.renderer.renderContext,this.createListElement(this.list[t])));
this.children.splice(t,0,this.renderer.renderTree.createRenderer(this.renderer,this.createListElement(this.list[t])));
this.renderer.domNode.insertBefore(this.children[t].renderInDom(),this.renderer.domNode.childNodes[t]);
// Ask the listview to animate the insertion
if(this.listview && this.listview.insert) {

View File

@ -28,7 +28,7 @@ NavigatorWidget.prototype.generate = function() {
this.attributes = {
"class": "tw-navigator"
};
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 = [
{name: "tw-navigate", handlerObject: this, handlerMethod: "handleNavigateEvent"},
{name: "tw-edit-tiddler", handlerObject: this, handlerMethod: "handleEditTiddlerEvent"},

View File

@ -31,7 +31,7 @@ RevealWidget.prototype.generate = function() {
// Compute the title of the state tiddler and read it
this.stateTitle = this.state;
if(this.qualifyTiddlerTitles) {
this.stateTitle = this.stateTitle + "-" + this.renderer.getContextScopeId();
this.stateTitle = this.stateTitle + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
}
this.readState();
// Set up the element attributes
@ -53,7 +53,7 @@ RevealWidget.prototype.generate = function() {
"class": classes.join(" "),
style: styles.join("")
};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,this.isOpen ? this.renderer.parseTreeNode.children : []);
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.isOpen ? this.renderer.parseTreeNode.children : []);
this.events = [{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"}];
};
@ -63,7 +63,7 @@ Read the state tiddler
RevealWidget.prototype.readState = function() {
// Read the information from the state tiddler
if(this.stateTitle) {
var state = this.renderer.renderTree.wiki.getTextReference(this.stateTitle,this["default"],this.renderer.getContextTiddlerTitle());
var state = this.renderer.renderTree.wiki.getTextReference(this.stateTitle,this["default"],this.renderer.tiddlerTitle);
switch(this.type) {
case "popup":
this.readPopupState(state);
@ -129,7 +129,7 @@ RevealWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers
this.readState();
// Construct the child nodes if required
if(this.isOpen && this.children.length === 0) {
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);
var parentNode = this.renderer.domNode;
$tw.utils.each(this.children,function(child) {
parentNode.appendChild(child.renderInDom());

View File

@ -32,7 +32,7 @@ SetStyleWidget.prototype.generate = function() {
if(this["class"]) {
this.attributes["class"] = this["class"];
}
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);
};
exports.setstyle = SetStyleWidget;

View File

@ -56,7 +56,7 @@ var TranscludeWidget = function(renderer) {
TranscludeWidget.prototype.generate = function() {
var tr, templateParseTree, templateTiddler;
// Get the render target details
this.targetTitle = this.renderer.getAttribute("target",this.renderer.getContextTiddlerTitle());
this.targetTitle = this.renderer.getAttribute("target",this.renderer.tiddlerTitle);
this.targetField = this.renderer.getAttribute("field");
this.targetIndex = this.renderer.getAttribute("index");
// Get the render tree for the template
@ -67,7 +67,7 @@ TranscludeWidget.prototype.generate = function() {
} else {
this.templateTitle = this.renderer.getAttribute("template",this.targetTitle);
// Check for recursion
if(this.renderer.checkContextRecursion({
if(this.renderer.renderTree.checkContextRecursion(this.renderer.parentRenderer,{
tiddlerTitle: this.targetTitle,
templateTitle: this.templateTitle
})) {
@ -101,11 +101,10 @@ TranscludeWidget.prototype.generate = function() {
if(!this.renderer.renderTree.wiki.tiddlerExists(this.targetTitle) && !this.renderer.renderTree.wiki.isShadowTiddler(this.targetTitle)) {
$tw.utils.pushTop(classes,"tw-tiddler-missing");
}
// Create the renderers for the wrapper and the children
var newRenderContext = {
// Save the context for this renderer node
this.renderer.context = {
tiddlerTitle: this.targetTitle,
templateTitle: this.templateTitle,
parentContext: this.renderer.renderContext
templateTitle: this.templateTitle
};
// Set the element
this.tag = this.renderer.parseTreeNode.isBlock ? "div" : "span";
@ -119,7 +118,7 @@ TranscludeWidget.prototype.generate = function() {
if(this.renderer.hasAttribute("tooltip")) {
this.attributes.title = this.renderer.getAttribute("tooltip");
}
this.children = this.renderer.renderTree.createRenderers(newRenderContext,templateParseTree);
this.children = this.renderer.renderTree.createRenderers(this.renderer,templateParseTree);
};
TranscludeWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {

View File

@ -23,7 +23,7 @@ VersionWidget.prototype.generate = function() {
// Set the element
this.tag = "span";
this.attributes = {};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
type: "text",
text: $tw.version
}]);

View File

@ -57,7 +57,7 @@ VideoWidget.prototype.generate = function() {
default:
this.tag = "div";
this.attributes = {};
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
type: "text",
text: "Unknown video type"
}]);

View File

@ -54,7 +54,7 @@ var ViewWidget = function(renderer) {
ViewWidget.prototype.generate = function() {
// Get parameters from our attributes
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.getContextTiddlerTitle());
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
this.fieldName = this.renderer.getAttribute("field","text");
this.format = this.renderer.getAttribute("format","text");
// Get the value to display

View File

@ -30,7 +30,7 @@ DateViewer.prototype.render = function() {
this.viewWidget.attributes = {
"class": "tw-view-date"
};
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
type: "text",
text: value
}]);

View File

@ -33,7 +33,7 @@ HtmlEncodedViewer.prototype.render = function() {
this.viewWidget.attributes = {
"class": "tw-view-htmlencoded"
};
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
type: "text",
text: $tw.utils.htmlEncode(value)
}]);

View File

@ -21,20 +21,17 @@ var HtmlWikifiedViewer = function(viewWidget,tiddler,field,value) {
HtmlWikifiedViewer.prototype.render = function() {
// Parse the field text
var newRenderContext = {
parentContext: this.viewWidget.renderer.renderContext
};
var wiki = this.viewWidget.renderer.renderTree.wiki,
parser = wiki.parseText("text/vnd.tiddlywiki",this.value),
renderTree = new $tw.WikiRenderTree(parser,{wiki: wiki});
renderTree.execute(newRenderContext);
renderTree.execute();
var text = renderTree.render("text/html");
// Set the element details
this.viewWidget.tag = "pre";
this.viewWidget.attributes = {
"class": "tw-view-htmlwikified"
};
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
type: "text",
text: text
}]);

View File

@ -33,7 +33,7 @@ JsEncodedViewer.prototype.render = function() {
this.viewWidget.attributes = {
"class": "tw-view-jsencoded"
};
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
type: "text",
text: $tw.utils.stringify(value)
}]);

View File

@ -26,7 +26,7 @@ LinkViewer.prototype.render = function() {
this.viewWidget.attributes = {
"class": "tw-view-link"
};
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
type: "element",
tag: "$link",
attributes: {

View File

@ -30,7 +30,7 @@ RelativeDateViewer.prototype.render = function() {
this.viewWidget.attributes = {
"class": "tw-view-date"
};
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
type: "text",
text: value
}]);

View File

@ -35,7 +35,7 @@ WikifiedViewer.prototype.render = function() {
if(this.tiddler && this.tiddler.fields.title) {
node.attributes.target = {type: "string", value: this.tiddler.fields.title}
}
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[node]);
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[node]);
};
exports.wikified = WikifiedViewer;

View File

@ -565,10 +565,10 @@ Parse text from a tiddler and render it into another format
outputType: content type for the output
title: title of the tiddler to be rendered
*/
exports.renderTiddler = function(outputType,title,renderContext) {
exports.renderTiddler = function(outputType,title,context) {
var parser = this.parseTiddler(title),
renderTree = new $tw.WikiRenderTree(parser,{wiki: this});
renderTree.execute(renderContext);
renderTree = new $tw.WikiRenderTree(parser,{wiki: this, context: context});
renderTree.execute();
return renderTree.render(outputType);
};

View File

@ -43,7 +43,7 @@ StripCommentsViewer.prototype.render = function() {
// Set the element details
this.viewWidget.tag = "span";
this.viewWidget.attributes = {};
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
type: "text",
text: value
}]);