1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2025-01-25 16:36:52 +00:00

Added protection against wikitext recursion

Now attempts to view a tiddler recursively fail gracefully
This commit is contained in:
Jeremy Ruston 2012-02-19 17:20:16 +00:00
parent 3bb0490bee
commit a0524c2144
6 changed files with 51 additions and 33 deletions

View File

@ -39,7 +39,7 @@ MacroNode.prototype.cloneChildren = function() {
return childClones; return childClones;
}; };
MacroNode.prototype.execute = function(tiddler) { MacroNode.prototype.execute = function(parents,tiddler) {
// Evaluate the macro parameters to get their values // Evaluate the macro parameters to get their values
if(typeof this.paramFn === "object") { if(typeof this.paramFn === "object") {
this.params = this.paramFn; this.params = this.paramFn;
@ -48,6 +48,8 @@ MacroNode.prototype.execute = function(tiddler) {
} }
// Save the context tiddler // Save the context tiddler
this.tiddlerTitle = tiddler.title; this.tiddlerTitle = tiddler.title;
// Save a reference to the array of parents
this.parents = parents;
// Render the macro to get its content // Render the macro to get its content
this.content = this.macro.execute(this,tiddler,this.store); this.content = this.macro.execute(this,tiddler,this.store);
}; };
@ -92,7 +94,7 @@ MacroNode.prototype.refresh = function(changes) {
if(this.dependencies.hasChanged(changes)) { if(this.dependencies.hasChanged(changes)) {
// Re-execute the macro if so // Re-execute the macro if so
var tiddler = this.store.getTiddler(this.tiddlerTitle); var tiddler = this.store.getTiddler(this.tiddlerTitle);
this.execute(tiddler); this.execute(this.parents,tiddler);
} else { } else {
// Refresh any children // Refresh any children
for(t=0; t<this.content.length; t++) { for(t=0; t<this.content.length; t++) {
@ -115,7 +117,7 @@ MacroNode.prototype.refreshInDom = function(changes) {
while(this.domNode.hasChildNodes()) { while(this.domNode.hasChildNodes()) {
this.domNode.removeChild(this.domNode.firstChild); this.domNode.removeChild(this.domNode.firstChild);
} }
this.execute(tiddler); this.execute(this.parents,tiddler);
for(t=0; t<this.content.length; t++) { for(t=0; t<this.content.length; t++) {
this.content[t].renderInDom(this.domNode); this.content[t].renderInDom(this.domNode);
} }
@ -149,10 +151,10 @@ ElementNode.prototype.clone = function() {
return new ElementNode(this.type,this.attributes,childClones); return new ElementNode(this.type,this.attributes,childClones);
}; };
ElementNode.prototype.execute = function(tiddler) { ElementNode.prototype.execute = function(parents,tiddler) {
if(this.children) { if(this.children) {
for(var t=0; t<this.children.length; t++) { for(var t=0; t<this.children.length; t++) {
this.children[t].execute(tiddler); this.children[t].execute(parents,tiddler);
} }
} }
}; };
@ -247,7 +249,7 @@ TextNode.prototype.clone = function() {
return this; return this;
}; };
TextNode.prototype.execute = function(tiddler) { TextNode.prototype.execute = function(parents,tiddler) {
// Text nodes don't need executing // Text nodes don't need executing
}; };
@ -280,7 +282,7 @@ EntityNode.prototype.clone = function() {
return this; return this;
}; };
EntityNode.prototype.execute = function(tiddler) { EntityNode.prototype.execute = function(parents,tiddler) {
// Entity nodes don't need executing // Entity nodes don't need executing
}; };
@ -313,7 +315,7 @@ RawNode.prototype.clone = function() {
return this; return this;
}; };
RawNode.prototype.execute = function(tiddler) { RawNode.prototype.execute = function(parents,tiddler) {
// Raw nodes don't need executing // Raw nodes don't need executing
}; };
@ -381,7 +383,7 @@ var SliderNode = function(type,label,tooltip,isOpen,children) {
attributes.alt = tooltip; attributes.alt = tooltip;
attributes.title = tooltip; attributes.title = tooltip;
} }
return ElementNode("div", return ElementNode("span",
attributes, attributes,
[ [
ElementNode("a", ElementNode("a",
@ -422,7 +424,7 @@ var Renderer = function(tiddlerTitle,templateTitle,store) {
// Execute the macros in the root // Execute the macros in the root
var tiddler = store.getTiddler(tiddlerTitle); var tiddler = store.getTiddler(tiddlerTitle);
for(t=0; t<this.steps.length; t++) { for(t=0; t<this.steps.length; t++) {
this.steps[t].execute(tiddler); this.steps[t].execute([templateTitle],tiddler);
} }
}; };

View File

@ -55,7 +55,7 @@ exports.macro = {
"class": classes "class": classes
},macroNode.cloneChildren())]; },macroNode.cloneChildren())];
for(var t=0; t<content.length; t++) { for(var t=0; t<content.length; t++) {
content[t].execute(tiddler); content[t].execute(macroNode.parents,tiddler);
} }
return content; return content;
} }

View File

@ -46,8 +46,11 @@ exports.macro = {
templateText = "<<view title link>>", templateText = "<<view title link>>",
template = macroNode.params.template ? store.getTiddler(macroNode.params.template) : null, template = macroNode.params.template ? store.getTiddler(macroNode.params.template) : null,
content = [], content = [],
t; t,
parents = macroNode.parents;
if(template) { if(template) {
parents = parents.slice(0);
parents.push(template.title);
templateType = template.type; templateType = template.type;
templateText = template.text; templateText = template.text;
} }
@ -64,7 +67,7 @@ exports.macro = {
cloneTemplate.push(templateTree[c].clone()); cloneTemplate.push(templateTree[c].clone());
} }
var listNode = Renderer.ElementNode("li",null,cloneTemplate); var listNode = Renderer.ElementNode("li",null,cloneTemplate);
listNode.execute(store.getTiddler(tiddlers[t])); listNode.execute(parents,store.getTiddler(tiddlers[t]));
content.push(listNode); content.push(listNode);
} }
return [Renderer.ElementNode("ul",null,content)]; return [Renderer.ElementNode("ul",null,content)];

View File

@ -54,7 +54,7 @@ exports.macro = {
dependencies.addDependency(macroNode.params.template,true); dependencies.addDependency(macroNode.params.template,true);
} }
var m = Renderer.MacroNode("tiddler",paramFn,null,dependencies,store); var m = Renderer.MacroNode("tiddler",paramFn,null,dependencies,store);
m.execute(tiddler); m.execute(macroNode.parents,tiddler);
content.push(m); content.push(m);
} }
return content; return content;
@ -89,7 +89,7 @@ exports.macro = {
dependencies.addDependency(template,true); dependencies.addDependency(template,true);
} }
var m = Renderer.MacroNode("tiddler",paramFn,null,dependencies,store); var m = Renderer.MacroNode("tiddler",paramFn,null,dependencies,store);
m.execute(store.getTiddler(targetTiddlers[t])); m.execute(macroNode.parents,store.getTiddler(targetTiddlers[t]));
m.renderInDom(macroNode.domNode,macroNode.domNode.childNodes[t]); m.renderInDom(macroNode.domNode,macroNode.domNode.childNodes[t]);
macroNode.content.splice(t,0,m); macroNode.content.splice(t,0,m);
} else { } else {

View File

@ -58,33 +58,39 @@ exports.macro = {
renderTemplate = macroNode.params.template, renderTemplate = macroNode.params.template,
content, content,
contentClone = [], contentClone = [],
t; t,
parents = macroNode.parents.slice(0);
if(typeof renderTitle !== "string") { if(typeof renderTitle !== "string") {
renderTitle = tiddler.title; renderTitle = tiddler.title;
} }
if(typeof renderTemplate !== "string") { if(typeof renderTemplate !== "string") {
renderTemplate = renderTitle; renderTemplate = renderTitle;
} }
if("with" in macroNode.params) { if(parents.indexOf(renderTemplate) === -1) {
// Parameterised transclusion if("with" in macroNode.params) {
var targetTiddler = store.getTiddler(renderTemplate), // Parameterised transclusion
text = targetTiddler.text; var targetTiddler = store.getTiddler(renderTemplate),
var withTokens = [macroNode.params["with"]]; text = targetTiddler.text;
for(t=0; t<withTokens.length; t++) { var withTokens = [macroNode.params["with"]];
var placeholderRegExp = new RegExp("\\$"+(t+1),"mg"); for(t=0; t<withTokens.length; t++) {
text = text.replace(placeholderRegExp,withTokens[t]); var placeholderRegExp = new RegExp("\\$"+(t+1),"mg");
text = text.replace(placeholderRegExp,withTokens[t]);
}
content = store.parseText(targetTiddler.type,text).tree;
} else {
// There's no parameterisation, so we can just render the target tiddler directly
var parseTree = store.parseTiddler(renderTemplate);
content = parseTree ? parseTree.tree : [];
} }
content = store.parseText(targetTiddler.type,text).tree;
} else { } else {
// There's no parameterisation, so we can just render the target tiddler directly content = [Renderer.TextNode("{{** Tiddler recursion error in <<tiddler>> macro **}}")];
var parseTree = store.parseTiddler(renderTemplate);
content = parseTree ? parseTree.tree : [];
} }
parents.push(renderTemplate);
for(t=0; t<content.length; t++) { for(t=0; t<content.length; t++) {
contentClone.push(content[t].clone()); contentClone.push(content[t].clone());
} }
for(t=0; t<contentClone.length; t++) { for(t=0; t<contentClone.length; t++) {
contentClone[t].execute(store.getTiddler(renderTitle)); contentClone[t].execute(parents,store.getTiddler(renderTitle));
} }
return contentClone; return contentClone;
} }

View File

@ -26,7 +26,8 @@ exports.macro = {
var v = tiddler[macroNode.params.field], var v = tiddler[macroNode.params.field],
content, content,
t, t,
contentClone = []; contentClone = [],
parents = macroNode.parents;
if(v !== undefined) { if(v !== undefined) {
switch(macroNode.params.format) { switch(macroNode.params.format) {
case "link": case "link":
@ -37,11 +38,17 @@ exports.macro = {
[Renderer.TextNode(v)], [Renderer.TextNode(v)],
dependencies, dependencies,
store); store);
link.execute(tiddler); link.execute(parents,tiddler);
return [link]; return [link];
case "wikified": case "wikified":
if(macroNode.params.field === "text") { if(macroNode.params.field === "text") {
content = store.parseTiddler(tiddler.title).tree; if(parents.indexOf(tiddler.title) === -1) {
content = store.parseTiddler(tiddler.title).tree;
} else {
content = [Renderer.TextNode("{{** Tiddler recursion error in <<view>> macro **}}")];
}
parents = parents.slice(0);
parents.push(tiddler.title);
} else { } else {
content = store.parseText("text/x-tiddlywiki",v).tree; content = store.parseText("text/x-tiddlywiki",v).tree;
} }
@ -49,7 +56,7 @@ exports.macro = {
contentClone.push(content[t].clone()); contentClone.push(content[t].clone());
} }
for(t=0; t<contentClone.length; t++) { for(t=0; t<contentClone.length; t++) {
contentClone[t].execute(tiddler); contentClone[t].execute(parents,tiddler);
} }
return contentClone; return contentClone;
case "date": case "date":