Hello guys,
recently I've stumbled upon a bug with the parametric transclusion and I'd
like to share it and the fix (hope this will go to the core as well).
*The bug.*
The usecase is the following: a template tiddler contains some listing
stuff, a newTiddler button etc, one of the parameters is meant to be a
filter. If you're interested, the whole thing looks like this ($1 is for
filter):
<<fet *filter '$1'* sortableBy '"$2"' script 'var wrapTitle =
function(text,tid){
return tid.tags.contains("emphasis") ?
"@@font-weight:bold;font-size:inherit;"+text+"@@" : text;
};
var wrapText = function(tiddler){
var text = "{{ti{<<tiddler [["+tiddler.title+"]]>"+">}}}";
var showWrap = tiddler.text ? (
" "+(tiddler.tags.contains("showInline") ? text :
((tiddler.tags.contains("show") ? "+" : "") +
("+++{{linkAsText{[>][:]}}}"+text+"==="))
)) : "";
return showWrap;
}' writeToList
'wrapTitle(tiddler.title,tiddler)+wrapText(tiddler)'>><<newTiddler $3
label:"add" text:"" title:"">> [[T|SListTemplate]]
The symptom is the following: as the whole thing is transcluded and
wikified (<<tiddler [[SListTemplate##main]]
*with:"[tag[current]]"*with:"orderCurrent" with:'tag:"current" tag:"steps"'>>),
it works as expected; but on refreshing I get a list of two tiddlers: tagand
current (the parts of the [tag[current]] filter).
*The explanation.*
The reason is in how config.macros.tiddler.handler and
config.macros.tiddler.transclude work:
the former sets an args attribute like this [1]:
wrapper.setAttribute("args","[["+args.join("]] [[")+"]]");
while args contain square brackets; and the latter reads it like this [2]
(typeof
args == "string" case is the refreshing case):
args = args.readBracketedList();
Obviously, we get ("[["+args.join("]] [[")+"]]").readBracketedList()instead
of just args, which is not the same in the case when args[i] contain a
square bracket.
*Possible fixes.*
To get rid of such a bug, we have to do smth with the square brackets.
Actually, not only with them, but with everything that parseParams [3]
considers special symbols. The first idea that came to me was to use
encodeURIComponent/decodeURIComponent, but they don't fit as some
characters are forbidden [4]. Ok, that's actually not URI, let's try escape/
unescape. Although they helped in my case [*], they are deprecated and are
not expected to work consistently with non-ASCII characters [5]. Right,
there's a solution proposed at [6], but it's not explained in details and
I'm not sure if it will work in every case.
May be you know some good and reliable way to "escape/unescape" the pesky
symbols for any line? May be it's worse to list all symbols considered
"special" by parseParams and just substitute them with \uXXXX stuff? Any
better ideas?
Best regards,
Yakov.
[1] https://github.com/TiddlyWiki/tiddlywiki/blob/master/js/Macros.js#L213
[2] https://github.com/TiddlyWiki/tiddlywiki/blob/master/js/Macros.js#L228
[3] https://github.com/TiddlyWiki/tiddlywiki/blob/master/js/Strings.js#L96
[4]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FencodeURIComponent
(see the first code block in description)
[5]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions?redirectlocale=en-US&redirectslug=JavaScript%2FGuide%2FFunctions#escape_and_unescape_functions(Obsoleted_above_JavaScript_1.5)
[6]
http://stackoverflow.com/questions/7499473/need-to-escape-non-ascii-characters-in-javascript
[*] the code was the following (no good way to hijack in a shorter way);
this is just to show what was changed:
config.macros.tiddler.handler =
function(place,macroName,params,wikifier,paramString,tiddler) {
var allowEval = true;
var stack = config.macros.tiddler.tiddlerStack;
if(stack.length > 0 && config.evaluateMacroParameters == "system") {
// included tiddler and "system" evaluation required, so check
tiddler tagged appropriately
var title = stack[stack.length-1];
var pos = title.indexOf(config.textPrimitives.sectionSeparator);
if(pos != -1)
title = title.substr(0,pos); // get the base tiddler title
var t = store.getTiddler(title);
if(!t || t.tags.indexOf("systemAllowEval") == -1)
allowEval = false;
}
params = paramString.parseParams("name",null,allowEval,false,true);
var names = params[0]["name"];
var tiddlerName = names[0];
var className = names[1] || null;
var args = params[0]["with"];
var wrapper = createTiddlyElement(place,"span",null,className,null,{
refresh: "content", tiddler: tiddlerName
});
* var escapedArgs = []* if(args!==undefined) {
* for(var i = 0; i < args.length; i++)
escapedArgs.push(escape(args[i]));
wrapper.setAttribute("args","[["+escapedArgs.join("]] [[")+"]]");
wrapper.setAttribute("readableArgs","[["+args.join("]] [[")+"]]"); //
useful for DOM inspection, not necessary* }
this.transclude(wrapper,tiddlerName,args);
};
config.macros.tiddler.transclude = function(wrapper,tiddlerName,args) {
var text = store.getTiddlerText(tiddlerName);
if(!text)
return;
var stack = config.macros.tiddler.tiddlerStack;
if(stack.indexOf(tiddlerName) !== -1)
return;
stack.push(tiddlerName);
try {
* var i;*
if(typeof args == "string") {
args = args.readBracketedList();
* for(i = 0; i < args.length; i++) args[i] =
unescape(args[i]);* }
var n = args ? Math.min(args.length,9) : 0;
for(i = 0; i < n; i++) {
var placeholderRE = new RegExp("\\$" + (i + 1),"mg");
text = text.replace(placeholderRE,args[i]);
}
config.macros.tiddler.renderText(wrapper,text,tiddlerName);
} finally {
stack.pop();
}
};
--
You received this message because you are subscribed to the Google Groups
"TiddlyWikiDev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/tiddlywikidev.
For more options, visit https://groups.google.com/groups/opt_out.