mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-15 22:34:51 +00:00
Merge branch 'master' into this-tiddler-reference
This commit is contained in:
commit
127ffbb078
@ -5,7 +5,7 @@
|
||||
# Default to the current version number for building the plugin library
|
||||
|
||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||
TW5_BUILD_VERSION=v5.2.6
|
||||
TW5_BUILD_VERSION=v5.2.8
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
|
@ -2,4 +2,4 @@
|
||||
|
||||
# Remove any output files
|
||||
|
||||
find . -regex "^./editions/[a-z0-9\.-]*/output/.*" -delete
|
||||
find . -regex "^./editions/.*/output/.*" -delete
|
||||
|
10
boot/boot.js
10
boot/boot.js
@ -1920,7 +1920,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
// Read the specification
|
||||
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
||||
// Helper to process a file
|
||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile) {
|
||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||
@ -1941,6 +1941,12 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
} else {
|
||||
var value = tiddler[name];
|
||||
switch(fieldInfo.source) {
|
||||
case "subdirectories":
|
||||
value = path.relative(rootPath, filename).split('/').slice(0, -1);
|
||||
break;
|
||||
case "filepath":
|
||||
value = path.relative(rootPath, filename);
|
||||
break;
|
||||
case "filename":
|
||||
value = path.basename(filename);
|
||||
break;
|
||||
@ -2023,7 +2029,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
var thisPath = path.relative(filepath, files[t]),
|
||||
filename = path.basename(thisPath);
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
|
||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -162,13 +162,13 @@ FramedEngine.prototype.fixHeight = function() {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
this.iframeNode.style.height = (newHeight + 14) + "px"; // +14 for the border on the textarea
|
||||
this.iframeNode.style.height = newHeight + "px";
|
||||
}
|
||||
} else {
|
||||
var fixedHeight = parseInt(this.widget.wiki.getTiddlerText(HEIGHT_VALUE_TITLE,"400px"),10);
|
||||
fixedHeight = Math.max(fixedHeight,20);
|
||||
this.domNode.style.height = fixedHeight + "px";
|
||||
this.iframeNode.style.height = (fixedHeight + 14) + "px";
|
||||
this.iframeNode.style.height = fixedHeight + "px";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -25,20 +25,10 @@ exports.cascade = function(operationSubFunction,options) {
|
||||
if(!filterFnList[index]) {
|
||||
filterFnList[index] = options.wiki.compileFilter(filter);
|
||||
}
|
||||
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler","")
|
||||
}));
|
||||
if(output.length !== 0) {
|
||||
result = output[0];
|
||||
return false;
|
||||
|
@ -19,23 +19,13 @@ exports.filter = function(operationSubFunction,options) {
|
||||
var resultsToRemove = [],
|
||||
index = 0;
|
||||
results.each(function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",""),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length
|
||||
}));
|
||||
if(filtered.length === 0) {
|
||||
resultsToRemove.push(title);
|
||||
}
|
||||
|
@ -21,23 +21,13 @@ exports.map = function(operationSubFunction,options) {
|
||||
flatten = (suffixes[0] && suffixes[0][0] === "flat") ? true : false;
|
||||
results.clear();
|
||||
$tw.utils.each(inputTitles,function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (inputTitles.length - 1 - index),
|
||||
"length": "" + inputTitles.length
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",""),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (inputTitles.length - 1 - index),
|
||||
"length": "" + inputTitles.length
|
||||
}));
|
||||
if(filtered.length && flatten) {
|
||||
$tw.utils.each(filtered,function(value) {
|
||||
results.push(value);
|
||||
|
@ -18,24 +18,14 @@ exports.reduce = function(operationSubFunction,options) {
|
||||
var accumulator = "",
|
||||
index = 0;
|
||||
results.each(function(title) {
|
||||
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length,
|
||||
"accumulator": "" + accumulator
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length,
|
||||
"accumulator": "" + accumulator
|
||||
}));
|
||||
if(list.length > 0) {
|
||||
accumulator = "" + list[0];
|
||||
}
|
||||
|
@ -25,20 +25,10 @@ exports.sort = function(operationSubFunction,options) {
|
||||
indexes = new Array(inputTitles.length),
|
||||
compareFn;
|
||||
results.each(function(title) {
|
||||
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
opts.variables = {
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
};
|
||||
if(name in opts.variables) {
|
||||
return opts.variables[name];
|
||||
} else {
|
||||
return widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
}));
|
||||
sortKeys.push(key[0] || "");
|
||||
});
|
||||
results.clear();
|
||||
|
@ -255,19 +255,21 @@ exports.compileFilter = function(filterString) {
|
||||
var operands = [],
|
||||
operatorFunction;
|
||||
if(!operator.operator) {
|
||||
// Use the "title" operator if no operator is specified
|
||||
operatorFunction = filterOperators.title;
|
||||
} else if(!filterOperators[operator.operator]) {
|
||||
operatorFunction = filterOperators.field;
|
||||
// Unknown operators treated as "[unknown]" - at run time we can distinguish between a custom operator and falling back to the default "field" operator
|
||||
operatorFunction = filterOperators["[unknown]"];
|
||||
} else {
|
||||
// Use the operator function
|
||||
operatorFunction = filterOperators[operator.operator];
|
||||
}
|
||||
|
||||
$tw.utils.each(operator.operands,function(operand) {
|
||||
if(operand.indirect) {
|
||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||
} else if(operand.variable) {
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
operand.value = widget.getVariable(varTree.name,{params:varTree.params,defaultValue: ""});
|
||||
operand.value = widget.evaluateVariable(varTree.name,{params: varTree.params, source: source})[0] || "";
|
||||
} else {
|
||||
operand.value = operand.text;
|
||||
}
|
||||
|
@ -20,19 +20,10 @@ exports.filter = function(source,operator,options) {
|
||||
results = [],
|
||||
target = operator.prefix !== "!";
|
||||
source(function(tiddler,title) {
|
||||
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return options.widget.getVariable("currentTiddler");
|
||||
default:
|
||||
return options.widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": options.widget.getVariable("currentTiddler","")
|
||||
}));
|
||||
if((list.length > 0) === target) {
|
||||
results.push(title);
|
||||
}
|
||||
|
32
core/modules/filters/function.js
Normal file
32
core/modules/filters/function.js
Normal file
@ -0,0 +1,32 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/function.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning those input titles that are returned from a function
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.function = function(source,operator,options) {
|
||||
var functionName = operator.operands[0],
|
||||
variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName);
|
||||
if(variableInfo && variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) {
|
||||
return options.widget.evaluateVariable(functionName,{params: operator.operands.slice(1), source: source});
|
||||
}
|
||||
// Return the input list if the function wasn't found
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
@ -26,27 +26,14 @@ exports.reduce = function(source,operator,options) {
|
||||
accumulator = operator.operands[1] || "";
|
||||
for(var index=0; index<results.length; index++) {
|
||||
var title = results[index],
|
||||
list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return options.widget.getVariable("currentTiddler");
|
||||
case "accumulator":
|
||||
return "" + accumulator;
|
||||
case "index":
|
||||
return "" + index;
|
||||
case "revIndex":
|
||||
return "" + (results.length - 1 - index);
|
||||
case "length":
|
||||
return "" + results.length;
|
||||
default:
|
||||
return options.widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": options.widget.getVariable("currentTiddler"),
|
||||
"accumulator": "" + accumulator,
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length
|
||||
}));
|
||||
if(list.length > 0) {
|
||||
accumulator = "" + list[0];
|
||||
}
|
||||
|
@ -25,19 +25,10 @@ exports.sortsub = function(source,operator,options) {
|
||||
inputTitles.push(title);
|
||||
var r = filterFn.call(options.wiki,function(iterator) {
|
||||
iterator(options.wiki.getTiddler(title),title);
|
||||
},{
|
||||
getVariable: function(name,opts) {
|
||||
opts = opts || {};
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
case "..currentTiddler":
|
||||
return options.widget.getVariable("currentTiddler");
|
||||
default:
|
||||
return options.widget.getVariable(name,opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
},options.widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": options.widget.getVariable("currentTiddler")
|
||||
}));
|
||||
sortKeys.push(r[0] || "");
|
||||
});
|
||||
// Rather than sorting the titles array, we'll sort the indexes so that we can consult both arrays
|
||||
|
@ -74,6 +74,113 @@ exports.join = makeStringReducingOperator(
|
||||
},null
|
||||
);
|
||||
|
||||
var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
|
||||
exports.levenshtein = makeStringBinaryOperator(
|
||||
function(a,b) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
diffs = dmpObject.diff_main(a,b);
|
||||
return [dmpObject.diff_levenshtein(diffs) + ""];
|
||||
}
|
||||
);
|
||||
|
||||
// these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
function diffLineWordMode(text1,text2,mode) {
|
||||
var dmpObject = new dmp.diff_match_patch();
|
||||
var a = diffPartsToChars(text1,text2,mode);
|
||||
var lineText1 = a.chars1;
|
||||
var lineText2 = a.chars2;
|
||||
var lineArray = a.lineArray;
|
||||
var diffs = dmpObject.diff_main(lineText1,lineText2,false);
|
||||
dmpObject.diff_charsToLines_(diffs,lineArray);
|
||||
return diffs;
|
||||
}
|
||||
|
||||
function diffPartsToChars(text1,text2,mode) {
|
||||
var lineArray = [];
|
||||
var lineHash = {};
|
||||
lineArray[0] = '';
|
||||
|
||||
function diff_linesToPartsMunge_(text,mode) {
|
||||
var chars = '';
|
||||
var lineStart = 0;
|
||||
var lineEnd = -1;
|
||||
var lineArrayLength = lineArray.length,
|
||||
regexpResult;
|
||||
var searchRegexp = /\W+/g;
|
||||
while(lineEnd < text.length - 1) {
|
||||
if(mode === "words") {
|
||||
regexpResult = searchRegexp.exec(text);
|
||||
lineEnd = searchRegexp.lastIndex;
|
||||
if(regexpResult === null) {
|
||||
lineEnd = text.length;
|
||||
}
|
||||
lineEnd = --lineEnd;
|
||||
} else {
|
||||
lineEnd = text.indexOf('\n', lineStart);
|
||||
if(lineEnd == -1) {
|
||||
lineEnd = text.length - 1;
|
||||
}
|
||||
}
|
||||
var line = text.substring(lineStart, lineEnd + 1);
|
||||
|
||||
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
|
||||
chars += String.fromCharCode(lineHash[line]);
|
||||
} else {
|
||||
if (lineArrayLength == maxLines) {
|
||||
line = text.substring(lineStart);
|
||||
lineEnd = text.length;
|
||||
}
|
||||
chars += String.fromCharCode(lineArrayLength);
|
||||
lineHash[line] = lineArrayLength;
|
||||
lineArray[lineArrayLength++] = line;
|
||||
}
|
||||
lineStart = lineEnd + 1;
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
var maxLines = 40000;
|
||||
var chars1 = diff_linesToPartsMunge_(text1,mode);
|
||||
maxLines = 65535;
|
||||
var chars2 = diff_linesToPartsMunge_(text2,mode);
|
||||
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
|
||||
};
|
||||
|
||||
exports.makepatches = function(source,operator,options) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
suffix = operator.suffix || "",
|
||||
result = [];
|
||||
|
||||
source(function(tiddler,title) {
|
||||
var diffs, patches;
|
||||
if(suffix === "lines" || suffix === "words") {
|
||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||
patches = dmpObject.patch_make(title,diffs);
|
||||
} else {
|
||||
patches = dmpObject.patch_make(title,operator.operand);
|
||||
}
|
||||
Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.applypatches = makeStringBinaryOperator(
|
||||
function(a,b) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
patches;
|
||||
try {
|
||||
patches = dmpObject.patch_fromText(b);
|
||||
} catch(e) {
|
||||
}
|
||||
if(patches) {
|
||||
return [dmpObject.patch_apply(patches,a)[0]];
|
||||
} else {
|
||||
return [a];
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function makeStringBinaryOperator(fnCalc) {
|
||||
return function(source,operator,options) {
|
||||
var result = [];
|
||||
@ -184,4 +291,4 @@ exports.charcode = function(source,operator,options) {
|
||||
return [chars.join("")];
|
||||
};
|
||||
|
||||
})();
|
||||
})();
|
45
core/modules/filters/unknown.js
Normal file
45
core/modules/filters/unknown.js
Normal file
@ -0,0 +1,45 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/unknown.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for handling unknown filter operators.
|
||||
|
||||
Not intended to be used directly by end users, hence the square brackets around the name.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var fieldFilterOperatorFn = require("$:/core/modules/filters/field.js").field;
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports["[unknown]"] = function(source,operator,options) {
|
||||
// Check for a user defined filter operator
|
||||
if(operator.operator.charAt(0) === ".") {
|
||||
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator);
|
||||
if(variableInfo && variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) {
|
||||
var list = options.widget.evaluateVariable(operator.operator,{params: operator.operands, source: source});
|
||||
if(operator.prefix === "!") {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
if(list.indexOf(title) === -1) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
} else {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Otherwise, use the "field" operator
|
||||
return fieldFilterOperatorFn(source,operator,options);
|
||||
};
|
||||
|
||||
})();
|
@ -28,6 +28,8 @@ var AudioParser = function(type,text,options) {
|
||||
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
||||
}
|
||||
this.tree = [element];
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
};
|
||||
|
||||
exports["audio/ogg"] = AudioParser;
|
||||
|
@ -23,7 +23,7 @@ var BinaryParser = function(type,text,options) {
|
||||
children: [{
|
||||
type: "transclude",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: BINARY_WARNING_MESSAGE}
|
||||
"$tiddler": {type: "string", value: BINARY_WARNING_MESSAGE}
|
||||
}
|
||||
}]
|
||||
};
|
||||
@ -38,7 +38,7 @@ var BinaryParser = function(type,text,options) {
|
||||
children: [{
|
||||
type: "transclude",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: EXPORT_BUTTON_IMAGE}
|
||||
"$tiddler": {type: "string", value: EXPORT_BUTTON_IMAGE}
|
||||
}
|
||||
}]
|
||||
};
|
||||
@ -64,6 +64,8 @@ var BinaryParser = function(type,text,options) {
|
||||
children: [warn, link]
|
||||
}
|
||||
this.tree = [element];
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
};
|
||||
|
||||
exports["application/octet-stream"] = BinaryParser;
|
||||
|
@ -52,6 +52,8 @@ var CsvParser = function(type,text,options) {
|
||||
tag = "td";
|
||||
this.tree[0].children[0].children[0].children.push(row);
|
||||
}
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
};
|
||||
|
||||
exports["text/csv"] = CsvParser;
|
||||
|
@ -29,6 +29,8 @@ var HtmlParser = function(type,text,options) {
|
||||
if($tw.wiki.getTiddlerText("$:/config/HtmlParser/DisableSandbox","no") !== "yes") {
|
||||
this.tree[0].attributes.sandbox = {type: "string", value: $tw.wiki.getTiddlerText("$:/config/HtmlParser/SandboxTokens","")};
|
||||
}
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
};
|
||||
|
||||
exports["text/html"] = HtmlParser;
|
||||
|
@ -28,6 +28,8 @@ var ImageParser = function(type,text,options) {
|
||||
}
|
||||
}
|
||||
this.tree = [element];
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
};
|
||||
|
||||
exports["image/svg+xml"] = ImageParser;
|
||||
|
@ -84,8 +84,7 @@ exports.parseTokenString = function(source,pos,token) {
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a token matching a regex at a specified position. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
||||
Use the "Y" (sticky) flag to avoid searching the entire rest of the string
|
||||
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenRegExp = function(source,pos,reToken) {
|
||||
var node = {
|
||||
@ -124,6 +123,36 @@ exports.parseStringLiteral = function(source,pos) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Returns an array of {name:} with an optional "default" property. Options include:
|
||||
requireParenthesis: require the parameter definition to be wrapped in parenthesis
|
||||
*/
|
||||
exports.parseParameterDefinition = function(paramString,options) {
|
||||
options = options || {};
|
||||
if(options.requireParenthesis) {
|
||||
var parenMatch = /^\s*\((.*)\)\s*$/g.exec(paramString);
|
||||
if(!parenMatch) {
|
||||
return [];
|
||||
}
|
||||
paramString = parenMatch[1];
|
||||
}
|
||||
var params = [],
|
||||
reParam = /\s*([^:),\s]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|([^,"'\s]+)))?/mg,
|
||||
paramMatch = reParam.exec(paramString);
|
||||
while(paramMatch) {
|
||||
// Save the parameter details
|
||||
var paramInfo = {name: paramMatch[1]},
|
||||
defaultValue = paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5];
|
||||
if(defaultValue !== undefined) {
|
||||
paramInfo["default"] = defaultValue;
|
||||
}
|
||||
params.push(paramInfo);
|
||||
// Look for the next parameter
|
||||
paramMatch = reParam.exec(paramString);
|
||||
}
|
||||
return params;
|
||||
};
|
||||
|
||||
exports.parseMacroParameters = function(node,source,pos) {
|
||||
// Process parameters
|
||||
var parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||
@ -146,7 +175,7 @@ exports.parseMacroParameter = function(source,pos) {
|
||||
start: pos
|
||||
};
|
||||
// Define our regexp
|
||||
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
|
||||
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the parameter
|
||||
@ -176,7 +205,36 @@ exports.parseMacroParameter = function(source,pos) {
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
|
||||
Look for a macro invocation. Returns null if not found, or {type: "transclude", attributes:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroInvocationAsTransclusion = function(source,pos) {
|
||||
var node = $tw.utils.parseMacroInvocation(source,pos);
|
||||
if(node) {
|
||||
var positionalName = 0,
|
||||
transclusion = {
|
||||
type: "transclude",
|
||||
start: node.start,
|
||||
end: node.end
|
||||
};
|
||||
$tw.utils.addAttributeToParseTreeNode(transclusion,"$variable",node.name);
|
||||
$tw.utils.each(node.params,function(param) {
|
||||
var name = param.name;
|
||||
if(name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
name = "$" + name;
|
||||
}
|
||||
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: name,type: "string", value: param.value, start: param.start, end: param.end});
|
||||
} else {
|
||||
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: (positionalName++) + "",type: "string", value: param.value, start: param.start, end: param.end});
|
||||
}
|
||||
});
|
||||
return transclusion;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, params:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroInvocation = function(source,pos) {
|
||||
var node = {
|
||||
@ -185,7 +243,7 @@ exports.parseMacroInvocation = function(source,pos) {
|
||||
params: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reMacroName = /([^\s>"'=]+)/y;
|
||||
var reMacroName = /([^\s>"'=]+)/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double less than sign
|
||||
@ -222,7 +280,7 @@ exports.parseFilterVariable = function(source) {
|
||||
params: [],
|
||||
},
|
||||
pos = 0,
|
||||
reName = /([^\s"']+)/y;
|
||||
reName = /([^\s"']+)/g;
|
||||
// If there is no whitespace or it is an empty string then there are no macro parameters
|
||||
if(/^\S*$/.test(source)) {
|
||||
node.name = source;
|
||||
@ -247,10 +305,10 @@ exports.parseAttribute = function(source,pos) {
|
||||
start: pos
|
||||
};
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'=]+)/y,
|
||||
reUnquotedAttribute = /([^\/\s<>"'=]+)/y,
|
||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/y;
|
||||
var reAttributeName = /([^\/\s>"'=]+)/g,
|
||||
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
|
||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Get the attribute name
|
||||
|
@ -25,6 +25,8 @@ var ImageParser = function(type,text,options) {
|
||||
element.attributes.src = {type: "string", value: "data:application/pdf;base64," + text};
|
||||
}
|
||||
this.tree = [element];
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
};
|
||||
|
||||
exports["application/pdf"] = ImageParser;
|
||||
|
@ -20,6 +20,8 @@ var TextParser = function(type,text,options) {
|
||||
language: {type: "string", value: type}
|
||||
}
|
||||
}];
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
};
|
||||
|
||||
exports["text/plain"] = TextParser;
|
||||
|
@ -28,6 +28,8 @@ var VideoParser = function(type,text,options) {
|
||||
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
||||
}
|
||||
this.tree = [element];
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
};
|
||||
|
||||
exports["video/ogg"] = VideoParser;
|
||||
|
97
core/modules/parsers/wikiparser/rules/fnprocdef.js
Normal file
97
core/modules/parsers/wikiparser/rules/fnprocdef.js
Normal file
@ -0,0 +1,97 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/wikiparser/rules/fnprocdef.js
|
||||
type: application/javascript
|
||||
module-type: wikirule
|
||||
|
||||
Wiki pragma rule for function, procedure and widget definitions
|
||||
|
||||
```
|
||||
\function name(param:defaultvalue,param2:defaultvalue)
|
||||
definition text
|
||||
\end
|
||||
|
||||
\procedure name(param:defaultvalue,param2:defaultvalue)
|
||||
definition text
|
||||
\end
|
||||
|
||||
\widget $mywidget(param:defaultvalue,param2:defaultvalue)
|
||||
definition text
|
||||
\end
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.name = "fnprocdef";
|
||||
exports.types = {pragma: true};
|
||||
|
||||
/*
|
||||
Instantiate parse rule
|
||||
*/
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /^\\(function|procedure|widget)\s+([^(\s]+)\((\s*([^)]*))?\)(\s*\r?\n)?/mg;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse the most recent match
|
||||
*/
|
||||
exports.parse = function() {
|
||||
// Move past the macro name and parameters
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Parse the parameters
|
||||
var params = [];
|
||||
if(this.match[3]) {
|
||||
params = $tw.utils.parseParameterDefinition(this.match[4]);
|
||||
}
|
||||
// Is this a multiline definition?
|
||||
var reEnd;
|
||||
if(this.match[5]) {
|
||||
// If so, the end of the body is marked with \end
|
||||
reEnd = new RegExp("(\\r?\\n\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[2]) + ")?(?:$|\\r?\\n))","mg");
|
||||
} else {
|
||||
// Otherwise, the end of the definition is marked by the end of the line
|
||||
reEnd = /($|\r?\n)/mg;
|
||||
// Move past any whitespace
|
||||
this.parser.pos = $tw.utils.skipWhiteSpace(this.parser.source,this.parser.pos);
|
||||
}
|
||||
// Find the end of the definition
|
||||
reEnd.lastIndex = this.parser.pos;
|
||||
var text,
|
||||
endMatch = reEnd.exec(this.parser.source);
|
||||
if(endMatch) {
|
||||
text = this.parser.source.substring(this.parser.pos,endMatch.index);
|
||||
this.parser.pos = endMatch.index + endMatch[0].length;
|
||||
} else {
|
||||
// We didn't find the end of the definition, so we'll make it blank
|
||||
text = "";
|
||||
}
|
||||
// Save the macro definition
|
||||
var parseTreeNodes = [{
|
||||
type: "set",
|
||||
attributes: {},
|
||||
children: [],
|
||||
params: params
|
||||
}];
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"name",this.match[2]);
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"value",text);
|
||||
if(this.match[1] === "function") {
|
||||
parseTreeNodes[0].isFunctionDefinition = true;
|
||||
} else if(this.match[1] === "procedure") {
|
||||
parseTreeNodes[0].isProcedureDefinition = true;
|
||||
} else if(this.match[1] === "widget") {
|
||||
parseTreeNodes[0].isWidgetDefinition = true;
|
||||
}
|
||||
if(this.parser.configTrimWhiteSpace) {
|
||||
parseTreeNodes[0].configTrimWhiteSpace = true;
|
||||
}
|
||||
return parseTreeNodes;
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -48,7 +48,7 @@ exports.parse = function() {
|
||||
// Advance the parser position to past the tag
|
||||
this.parser.pos = tag.end;
|
||||
// Check for an immediately following double linebreak
|
||||
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
|
||||
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
||||
// Set whether we're in block mode
|
||||
tag.isBlock = this.is.block || hasLineBreak;
|
||||
// Parse the body if we need to
|
||||
@ -78,7 +78,7 @@ exports.parseTag = function(source,pos,options) {
|
||||
orderedAttributes: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reTagName = /([a-zA-Z0-9\-\$]+)/y;
|
||||
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a less than sign
|
||||
@ -93,9 +93,6 @@ exports.parseTag = function(source,pos,options) {
|
||||
return null;
|
||||
}
|
||||
node.tag = token.match[1];
|
||||
if(node.tag.slice(1).indexOf("$") !== -1) {
|
||||
return null;
|
||||
}
|
||||
if(node.tag.charAt(0) === "$") {
|
||||
node.type = node.tag.substr(1);
|
||||
}
|
||||
@ -129,7 +126,7 @@ exports.parseTag = function(source,pos,options) {
|
||||
pos = token.end;
|
||||
// Check for a required line break
|
||||
if(options.requireLineBreak) {
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ exports.parseImage = function(source,pos) {
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Get the source up to the terminating `]]`
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/y);
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ exports.findNextMatch = function(startPos) {
|
||||
var nextStart = startPos;
|
||||
// Try parsing at all possible macrocall openers until we match
|
||||
while((nextStart = this.parser.source.indexOf("<<",nextStart)) >= 0) {
|
||||
var nextCall = $tw.utils.parseMacroInvocation(this.parser.source,nextStart);
|
||||
var nextCall = $tw.utils.parseMacroInvocationAsTransclusion(this.parser.source,nextStart);
|
||||
if(nextCall) {
|
||||
var c = this.parser.source.charAt(nextCall.end);
|
||||
// Ensure EOL after parsed macro
|
||||
|
@ -27,7 +27,7 @@ exports.findNextMatch = function(startPos) {
|
||||
var nextStart = startPos;
|
||||
// Try parsing at all possible macrocall openers until we match
|
||||
while((nextStart = this.parser.source.indexOf("<<",nextStart)) >= 0) {
|
||||
this.nextCall = $tw.utils.parseMacroInvocation(this.parser.source,nextStart);
|
||||
this.nextCall = $tw.utils.parseMacroInvocationAsTransclusion(this.parser.source,nextStart);
|
||||
if(this.nextCall) {
|
||||
return nextStart;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ exports.parse = function() {
|
||||
var reEnd;
|
||||
if(this.match[3]) {
|
||||
// If so, the end of the body is marked with \end
|
||||
reEnd = new RegExp("(\\r?\\n\\s*\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[1]) + ")?(?:$|\\r?\\n))","mg");
|
||||
reEnd = new RegExp("(\\r?\\n[^\\S\\n\\r]*\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[1]) + ")?(?:$|\\r?\\n))","mg");
|
||||
} else {
|
||||
// Otherwise, the end of the definition is marked by the end of the line
|
||||
reEnd = /($|\r?\n)/mg;
|
||||
@ -77,16 +77,16 @@ exports.parse = function() {
|
||||
text = "";
|
||||
}
|
||||
// Save the macro definition
|
||||
return [{
|
||||
var parseTreeNodes = [{
|
||||
type: "set",
|
||||
attributes: {
|
||||
name: {type: "string", value: this.match[1]},
|
||||
value: {type: "string", value: text}
|
||||
},
|
||||
attributes: {},
|
||||
children: [],
|
||||
params: params,
|
||||
isMacroDefinition: true
|
||||
}];
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"name",this.match[1]);
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"value",text);
|
||||
return parseTreeNodes;
|
||||
};
|
||||
|
||||
})();
|
||||
|
60
core/modules/parsers/wikiparser/rules/parameters.js
Normal file
60
core/modules/parsers/wikiparser/rules/parameters.js
Normal file
@ -0,0 +1,60 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/wikiparser/rules/parameters.js
|
||||
type: application/javascript
|
||||
module-type: wikirule
|
||||
|
||||
Wiki pragma rule for parameter definitions
|
||||
|
||||
```
|
||||
\parameters(param:defaultvalue,param2:defaultvalue)
|
||||
definition text
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.name = "parameters";
|
||||
exports.types = {pragma: true};
|
||||
|
||||
/*
|
||||
Instantiate parse rule
|
||||
*/
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /^\\parameters\s*\(([^)]*)\)\s*\r?\n/mg;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse the most recent match
|
||||
*/
|
||||
exports.parse = function() {
|
||||
// Move past the macro name and parameters
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Parse the parameters
|
||||
var params = $tw.utils.parseParameterDefinition(this.match[1]);
|
||||
var attributes = Object.create(null),
|
||||
orderedAttributes = [];
|
||||
$tw.utils.each(params,function(param) {
|
||||
var name = param.name;
|
||||
// Parameter names starting with dollar must be escaped to double dollars for the parameters widget
|
||||
if(name.charAt(0) === "$") {
|
||||
name = "$" + name;
|
||||
}
|
||||
var attribute = {name: name, type: "string", value: param["default"] || ""};
|
||||
attributes[name] = attribute;
|
||||
orderedAttributes.push(attribute);
|
||||
});
|
||||
// Save the macro definition
|
||||
return [{
|
||||
type: "parameters",
|
||||
attributes: attributes,
|
||||
orderedAttributes: orderedAttributes
|
||||
}];
|
||||
};
|
||||
|
||||
})();
|
@ -23,7 +23,7 @@ exports.types = {block: true};
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?\}\}(?:\r?\n|$)/mg;
|
||||
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}(?:\r?\n|$)/mg;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
@ -31,13 +31,22 @@ exports.parse = function() {
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Get the match details
|
||||
var template = $tw.utils.trim(this.match[2]),
|
||||
textRef = $tw.utils.trim(this.match[1]);
|
||||
textRef = $tw.utils.trim(this.match[1]),
|
||||
params = this.match[3] ? this.match[3].split("|") : [];
|
||||
// Prepare the transclude widget
|
||||
var transcludeNode = {
|
||||
type: "transclude",
|
||||
attributes: {},
|
||||
isBlock: true
|
||||
};
|
||||
$tw.utils.each(params,function(paramValue,index) {
|
||||
var name = "" + index;
|
||||
transcludeNode.attributes[name] = {
|
||||
name: name,
|
||||
type: "string",
|
||||
value: paramValue
|
||||
}
|
||||
});
|
||||
// Prepare the tiddler widget
|
||||
var tr, targetTitle, targetField, targetIndex, tiddlerNode;
|
||||
if(textRef) {
|
||||
@ -48,14 +57,14 @@ exports.parse = function() {
|
||||
tiddlerNode = {
|
||||
type: "tiddler",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: targetTitle}
|
||||
tiddler: {name: "tiddler", type: "string", value: targetTitle}
|
||||
},
|
||||
isBlock: true,
|
||||
children: [transcludeNode]
|
||||
};
|
||||
}
|
||||
if(template) {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: template};
|
||||
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: template};
|
||||
if(textRef) {
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
@ -63,12 +72,12 @@ exports.parse = function() {
|
||||
}
|
||||
} else {
|
||||
if(textRef) {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
|
||||
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: targetTitle};
|
||||
if(targetField) {
|
||||
transcludeNode.attributes.field = {type: "string", value: targetField};
|
||||
transcludeNode.attributes["$field"] = {name: "$field", type: "string", value: targetField};
|
||||
}
|
||||
if(targetIndex) {
|
||||
transcludeNode.attributes.index = {type: "string", value: targetIndex};
|
||||
transcludeNode.attributes["$index"] = {name: "$index", type: "string", value: targetIndex};
|
||||
}
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
|
@ -23,7 +23,7 @@ exports.types = {inline: true};
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?\}\}/mg;
|
||||
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}/mg;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
@ -31,12 +31,21 @@ exports.parse = function() {
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Get the match details
|
||||
var template = $tw.utils.trim(this.match[2]),
|
||||
textRef = $tw.utils.trim(this.match[1]);
|
||||
textRef = $tw.utils.trim(this.match[1]),
|
||||
params = this.match[3] ? this.match[3].split("|") : [];
|
||||
// Prepare the transclude widget
|
||||
var transcludeNode = {
|
||||
type: "transclude",
|
||||
attributes: {}
|
||||
};
|
||||
$tw.utils.each(params,function(paramValue,index) {
|
||||
var name = "" + index;
|
||||
transcludeNode.attributes[name] = {
|
||||
name: name,
|
||||
type: "string",
|
||||
value: paramValue
|
||||
}
|
||||
});
|
||||
// Prepare the tiddler widget
|
||||
var tr, targetTitle, targetField, targetIndex, tiddlerNode;
|
||||
if(textRef) {
|
||||
@ -47,13 +56,13 @@ exports.parse = function() {
|
||||
tiddlerNode = {
|
||||
type: "tiddler",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: targetTitle}
|
||||
tiddler: {name: "tiddler", type: "string", value: targetTitle}
|
||||
},
|
||||
children: [transcludeNode]
|
||||
};
|
||||
}
|
||||
if(template) {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: template};
|
||||
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: template};
|
||||
if(textRef) {
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
@ -61,12 +70,12 @@ exports.parse = function() {
|
||||
}
|
||||
} else {
|
||||
if(textRef) {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
|
||||
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: targetTitle};
|
||||
if(targetField) {
|
||||
transcludeNode.attributes.field = {type: "string", value: targetField};
|
||||
transcludeNode.attributes["$field"] = {name: "$field", type: "string", value: targetField};
|
||||
}
|
||||
if(targetIndex) {
|
||||
transcludeNode.attributes.index = {type: "string", value: targetIndex};
|
||||
transcludeNode.attributes["$index"] = {name: "$index", type: "string", value: targetIndex};
|
||||
}
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
|
@ -32,6 +32,7 @@ options: see below:
|
||||
parseAsInline: true to parse text as inline instead of block
|
||||
wiki: reference to wiki to use
|
||||
_canonical_uri: optional URI of content if text is missing or empty
|
||||
configTrimWhiteSpace: true to trim whitespace
|
||||
*/
|
||||
var WikiParser = function(type,text,options) {
|
||||
this.wiki = options.wiki;
|
||||
@ -46,7 +47,7 @@ var WikiParser = function(type,text,options) {
|
||||
this.source = text || "";
|
||||
this.sourceLength = this.source.length;
|
||||
// Flag for ignoring whitespace
|
||||
this.configTrimWhiteSpace = false;
|
||||
this.configTrimWhiteSpace = options.configTrimWhiteSpace !== undefined ? options.configTrimWhiteSpace : false;
|
||||
// Parser mode
|
||||
this.parseAsInline = options.parseAsInline;
|
||||
// Set current parse position
|
||||
|
30
core/modules/widgets/fill.js
Normal file
30
core/modules/widgets/fill.js
Normal file
@ -0,0 +1,30 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/fill.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Sub-widget used by the transclude widget for specifying values for slots within transcluded content. It doesn't do anything by itself because the transclude widget only ever deals with the parse tree nodes, and doesn't instantiate the widget itself
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var FillWidget = function(parseTreeNode,options) {
|
||||
// Initialise
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
FillWidget.prototype = new Widget();
|
||||
|
||||
exports.fill = FillWidget;
|
||||
|
||||
})();
|
||||
|
@ -52,38 +52,44 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
|
||||
var parser = widgetPointer.wiki.parseTiddler(title,{parseAsInline:true});
|
||||
if(parser) {
|
||||
var parseTreeNode = parser.tree[0];
|
||||
while(parseTreeNode && parseTreeNode.type === "set") {
|
||||
while(parseTreeNode && ["setvariable","set","parameters"].indexOf(parseTreeNode.type) !== -1) {
|
||||
var node = {
|
||||
type: "set",
|
||||
attributes: parseTreeNode.attributes,
|
||||
params: parseTreeNode.params,
|
||||
isMacroDefinition: parseTreeNode.isMacroDefinition
|
||||
isMacroDefinition: parseTreeNode.isMacroDefinition,
|
||||
isFunctionDefinition: parseTreeNode.isFunctionDefinition,
|
||||
isProcedureDefinition: parseTreeNode.isProcedureDefinition,
|
||||
isWidgetDefinition: parseTreeNode.isWidgetDefinition,
|
||||
configTrimWhiteSpace: parseTreeNode.configTrimWhiteSpace
|
||||
};
|
||||
if (parseTreeNode.isMacroDefinition) {
|
||||
// Macro definitions can be folded into
|
||||
// current widget instead of adding
|
||||
// another link to the chain.
|
||||
var widget = widgetPointer.makeChildWidget(node);
|
||||
widget.computeAttributes();
|
||||
widget.execute();
|
||||
// We SHALLOW copy over all variables
|
||||
// in widget. We can't use
|
||||
// $tw.utils.assign, because that copies
|
||||
// up the prototype chain, which we
|
||||
// don't want.
|
||||
$tw.utils.each(Object.keys(widget.variables), function(key) {
|
||||
widgetPointer.variables[key] = widget.variables[key];
|
||||
});
|
||||
} else {
|
||||
widgetPointer.children = [widgetPointer.makeChildWidget(node)];
|
||||
// No more regenerating children for
|
||||
// this widget. If it needs to refresh,
|
||||
// it'll do so along with the the whole
|
||||
// importvariable tree.
|
||||
if (widgetPointer != this) {
|
||||
widgetPointer.makeChildWidgets = function(){};
|
||||
if(parseTreeNode.type === "set" || parseTreeNode.type === "setvariable") {
|
||||
if(parseTreeNode.isMacroDefinition || parseTreeNode.isProcedureDefinition || parseTreeNode.isWidgetDefinition || parseTreeNode.isFunctionDefinition) {
|
||||
// Macro definitions can be folded into
|
||||
// current widget instead of adding
|
||||
// another link to the chain.
|
||||
var widget = widgetPointer.makeChildWidget(node);
|
||||
widget.computeAttributes();
|
||||
widget.execute();
|
||||
// We SHALLOW copy over all variables
|
||||
// in widget. We can't use
|
||||
// $tw.utils.assign, because that copies
|
||||
// up the prototype chain, which we
|
||||
// don't want.
|
||||
$tw.utils.each(Object.keys(widget.variables), function(key) {
|
||||
widgetPointer.variables[key] = widget.variables[key];
|
||||
});
|
||||
} else {
|
||||
widgetPointer.children = [widgetPointer.makeChildWidget(node)];
|
||||
// No more regenerating children for
|
||||
// this widget. If it needs to refresh,
|
||||
// it'll do so along with the the whole
|
||||
// importvariable tree.
|
||||
if (widgetPointer != this) {
|
||||
widgetPointer.makeChildWidgets = function(){};
|
||||
}
|
||||
widgetPointer = widgetPointer.children[0];
|
||||
}
|
||||
widgetPointer = widgetPointer.children[0];
|
||||
}
|
||||
parseTreeNode = parseTreeNode.children && parseTreeNode.children[0];
|
||||
}
|
||||
|
@ -53,7 +53,9 @@ LetWidget.prototype.computeAttributes = function() {
|
||||
name = attribute.name;
|
||||
// Now that it's prepped, we're allowed to look this variable up
|
||||
// when defining later variables
|
||||
self.currentValueFor[name] = value;
|
||||
if(value !== undefined) {
|
||||
self.currentValueFor[name] = value;
|
||||
}
|
||||
});
|
||||
// Run through again, setting variables and looking for differences
|
||||
$tw.utils.each(this.currentValueFor,function(value,name) {
|
||||
@ -74,9 +76,7 @@ LetWidget.prototype.getVariableInfo = function(name,options) {
|
||||
text: this.currentValueFor[name]
|
||||
};
|
||||
}
|
||||
return Widget.prototype.getVariableInfo.call(this,name,$tw.utils.extend(Object.create(null),options,{
|
||||
defaultValue: ""
|
||||
}));
|
||||
return Widget.prototype.getVariableInfo.call(this,name,options);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -37,7 +37,7 @@ MacroCallWidget.prototype.render = function(parent,nextSibling) {
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
MacroCallWidget.prototype.execute = function() {
|
||||
// Get the parse type if specified
|
||||
this.macroName = this.parseTreeNode.name || this.getAttribute("$name"),
|
||||
this.parseType = this.getAttribute("$type","text/vnd.tiddlywiki");
|
||||
this.renderOutput = this.getAttribute("$output","text/html");
|
||||
// Merge together the parameters specified in the parse tree with the specified attributes
|
||||
@ -47,49 +47,26 @@ MacroCallWidget.prototype.execute = function() {
|
||||
params.push({name: name, value: attribute});
|
||||
}
|
||||
});
|
||||
// Get the macro value
|
||||
var macroName = this.parseTreeNode.name || this.getAttribute("$name"),
|
||||
variableInfo = this.getVariableInfo(macroName,{params: params}),
|
||||
text = variableInfo.text,
|
||||
parseTreeNodes;
|
||||
// Are we rendering to HTML?
|
||||
if(this.renderOutput === "text/html") {
|
||||
// If so we'll return the parsed macro
|
||||
// Check if we've already cached parsing this macro
|
||||
var mode = this.parseTreeNode.isBlock ? "blockParser" : "inlineParser",
|
||||
parser;
|
||||
if(variableInfo.srcVariable && variableInfo.srcVariable[mode]) {
|
||||
parser = variableInfo.srcVariable[mode];
|
||||
} else {
|
||||
parser = this.wiki.parseText(this.parseType,text,
|
||||
{parseAsInline: !this.parseTreeNode.isBlock});
|
||||
if(variableInfo.isCacheable && variableInfo.srcVariable) {
|
||||
variableInfo.srcVariable[mode] = parser;
|
||||
}
|
||||
}
|
||||
var parseTreeNodes = parser ? parser.tree : [];
|
||||
// Wrap the parse tree in a vars widget assigning the parameters to variables named "__paramname__"
|
||||
var attributes = {};
|
||||
$tw.utils.each(variableInfo.params,function(param) {
|
||||
var name = "__" + param.name + "__";
|
||||
attributes[name] = {
|
||||
name: name,
|
||||
type: "string",
|
||||
value: param.value
|
||||
};
|
||||
});
|
||||
// Make a transclude widget
|
||||
var positionalName = 0,
|
||||
parseTreeNodes = [{
|
||||
type: "vars",
|
||||
attributes: attributes,
|
||||
children: parseTreeNodes
|
||||
type: "transclude",
|
||||
isBlock: this.parseTreeNode.isBlock
|
||||
}];
|
||||
} else if(this.renderOutput === "text/raw") {
|
||||
parseTreeNodes = [{type: "text", text: text}];
|
||||
} else {
|
||||
// Otherwise, we'll render the text
|
||||
var plainText = this.wiki.renderText("text/plain",this.parseType,text,{parentWidget: this});
|
||||
parseTreeNodes = [{type: "text", text: plainText}];
|
||||
}
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"$variable",this.macroName);
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"$type",this.parseType);
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"$output",this.renderOutput);
|
||||
$tw.utils.each(params,function(param) {
|
||||
var name = param.name;
|
||||
if(name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
name = "$" + name;
|
||||
}
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],name,param.value);
|
||||
} else {
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],(positionalName++) + "",param.value);
|
||||
}
|
||||
});
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets(parseTreeNodes);
|
||||
};
|
||||
|
96
core/modules/widgets/parameters.js
Normal file
96
core/modules/widgets/parameters.js
Normal file
@ -0,0 +1,96 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/parameters.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Widget for definition of transclusion parameters
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget,
|
||||
TranscludeWidget = require("$:/core/modules/widgets/transclude.js").transclude;
|
||||
|
||||
var ParametersWidget = function(parseTreeNode,options) {
|
||||
// Initialise
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
ParametersWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
ParametersWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Call the constructor
|
||||
Widget.call(this);
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
ParametersWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
this.parametersDepth = Math.max(parseInt(this.getAttribute("$depth","1"),10) || 1,1);
|
||||
// Find the parent transclusions
|
||||
var pointer = this.parentWidget,
|
||||
depth = this.parametersDepth;
|
||||
while(pointer) {
|
||||
if(pointer instanceof TranscludeWidget) {
|
||||
depth--;
|
||||
if(depth <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pointer = pointer.parentWidget;
|
||||
}
|
||||
// Process each parameter
|
||||
if(pointer instanceof TranscludeWidget) {
|
||||
// Get the value for each defined parameter
|
||||
$tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(self.parseTreeNode),function(attr,index) {
|
||||
var name = attr.name;
|
||||
// If the attribute name starts with $$ then reduce to a single dollar
|
||||
if(name.substr(0,2) === "$$") {
|
||||
name = name.substr(1);
|
||||
}
|
||||
var value = pointer.getTransclusionParameter(name,index,self.getAttribute(attr.name,""));
|
||||
self.setVariable(name,value);
|
||||
});
|
||||
// Assign any metaparameters
|
||||
$tw.utils.each(pointer.getTransclusionMetaParameters(),function(getValue,name) {
|
||||
var variableName = self.getAttribute("$" + name);
|
||||
if(variableName) {
|
||||
self.setVariable(variableName,getValue(name));
|
||||
}
|
||||
});
|
||||
}
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
ParametersWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(Object.keys(changedAttributes).length) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports.parameters = ParametersWidget;
|
||||
|
||||
})();
|
@ -48,7 +48,17 @@ SetWidget.prototype.execute = function() {
|
||||
this.setValue = this.getAttribute("value");
|
||||
this.setEmptyValue = this.getAttribute("emptyValue");
|
||||
// Set context variable
|
||||
this.setVariable(this.setName,this.getValue(),this.parseTreeNode.params,!!this.parseTreeNode.isMacroDefinition);
|
||||
if(this.parseTreeNode.isMacroDefinition) {
|
||||
this.setVariable(this.setName,this.getValue(),this.parseTreeNode.params,true);
|
||||
} else if(this.parseTreeNode.isFunctionDefinition) {
|
||||
this.setVariable(this.setName,this.getValue(),this.parseTreeNode.params,undefined,{isFunctionDefinition: true});
|
||||
} else if(this.parseTreeNode.isProcedureDefinition) {
|
||||
this.setVariable(this.setName,this.getValue(),this.parseTreeNode.params,undefined,{isProcedureDefinition: true, configTrimWhiteSpace: this.parseTreeNode.configTrimWhiteSpace});
|
||||
} else if(this.parseTreeNode.isWidgetDefinition) {
|
||||
this.setVariable(this.setName,this.getValue(),this.parseTreeNode.params,undefined,{isWidgetDefinition: true, configTrimWhiteSpace: this.parseTreeNode.configTrimWhiteSpace});
|
||||
} else {
|
||||
this.setVariable(this.setName,this.getValue());
|
||||
}
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
82
core/modules/widgets/slot.js
Normal file
82
core/modules/widgets/slot.js
Normal file
@ -0,0 +1,82 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/slot.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Widget for definition of slots within transcluded content. The values provided by the translusion are passed to the slot.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget,
|
||||
TranscludeWidget = require("$:/core/modules/widgets/transclude.js").transclude;
|
||||
|
||||
var SlotWidget = function(parseTreeNode,options) {
|
||||
// Initialise
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
SlotWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
SlotWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Call the constructor
|
||||
Widget.call(this);
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
SlotWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
this.slotName = this.getAttribute("$name");
|
||||
this.slotDepth = parseInt(this.getAttribute("$depth","1"),10) || 1;
|
||||
// Find the parent transclusions
|
||||
var pointer = this.parentWidget,
|
||||
depth = this.slotDepth;
|
||||
while(pointer) {
|
||||
if(pointer instanceof TranscludeWidget) {
|
||||
depth--;
|
||||
if(depth <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pointer = pointer.parentWidget;
|
||||
}
|
||||
var parseTreeNodes = [{type: "text", attributes: {text: {type: "string", value: "Missing slot reference!"}}}];
|
||||
if(pointer instanceof TranscludeWidget) {
|
||||
// Get the parse tree nodes comprising the slot contents
|
||||
parseTreeNodes = pointer.getTransclusionSlotFill(this.slotName,this.parseTreeNode.children);
|
||||
}
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets(parseTreeNodes);
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
SlotWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["$name"] || changedAttributes["$depth"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports.slot = SlotWidget;
|
||||
|
||||
})();
|
@ -37,48 +37,349 @@ TranscludeWidget.prototype.render = function(parent,nextSibling) {
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
TranscludeWidget.prototype.execute = function() {
|
||||
// Get our parameters
|
||||
this.transcludeTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
|
||||
this.transcludeSubTiddler = this.getAttribute("subtiddler");
|
||||
this.transcludeField = this.getAttribute("field");
|
||||
this.transcludeIndex = this.getAttribute("index");
|
||||
this.transcludeMode = this.getAttribute("mode");
|
||||
this.recursionMarker = this.getAttribute("recursionMarker","yes");
|
||||
// Parse the text reference
|
||||
// Get our attributes, string parameters, and slot values into properties of the widget object
|
||||
this.collectAttributes();
|
||||
this.collectStringParameters();
|
||||
this.collectSlotFillParameters();
|
||||
// Get the parse tree nodes that we are transcluding
|
||||
var target = this.getTransclusionTarget(),
|
||||
parseTreeNodes = target.parseTreeNodes;
|
||||
this.sourceText = target.text;
|
||||
this.sourceType = target.type;
|
||||
this.parseAsInline = target.parseAsInline;
|
||||
// Process the transclusion according to the output type
|
||||
switch(this.transcludeOutput || "text/html") {
|
||||
case "text/html":
|
||||
// No further processing required
|
||||
break;
|
||||
case "text/raw":
|
||||
// Just return the raw text
|
||||
parseTreeNodes = [{type: "text", text: this.sourceText}];
|
||||
break;
|
||||
default:
|
||||
// text/plain
|
||||
var plainText = this.wiki.renderText("text/plain",this.sourceType,this.sourceText,{parentWidget: this});
|
||||
parseTreeNodes = [{type: "text", text: plainText}];
|
||||
break;
|
||||
}
|
||||
// Set the legacy transclusion context variables only if we're not transcluding a variable
|
||||
if(!this.transcludeVariable) {
|
||||
var recursionMarker = this.makeRecursionMarker();
|
||||
this.setVariable("transclusion",recursionMarker);
|
||||
}
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets(parseTreeNodes);
|
||||
};
|
||||
|
||||
/*
|
||||
Collect the attributes we need, in the process determining whether we're being used in legacy mode
|
||||
*/
|
||||
TranscludeWidget.prototype.collectAttributes = function() {
|
||||
var self = this;
|
||||
// Detect legacy mode
|
||||
this.legacyMode = true;
|
||||
$tw.utils.each(this.attributes,function(value,name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
self.legacyMode = false;
|
||||
}
|
||||
});
|
||||
// Get the attributes for the appropriate mode
|
||||
if(this.legacyMode) {
|
||||
this.transcludeTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
|
||||
this.transcludeSubTiddler = this.getAttribute("subtiddler");
|
||||
this.transcludeField = this.getAttribute("field");
|
||||
this.transcludeIndex = this.getAttribute("index");
|
||||
this.transcludeMode = this.getAttribute("mode");
|
||||
this.recursionMarker = this.getAttribute("recursionMarker","yes");
|
||||
} else {
|
||||
this.transcludeVariable = this.getAttribute("$variable");
|
||||
this.transcludeType = this.getAttribute("$type");
|
||||
this.transcludeOutput = this.getAttribute("$output","text/html");
|
||||
this.transcludeTitle = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
||||
this.transcludeSubTiddler = this.getAttribute("$subtiddler");
|
||||
this.transcludeField = this.getAttribute("$field");
|
||||
this.transcludeIndex = this.getAttribute("$index");
|
||||
this.transcludeMode = this.getAttribute("$mode");
|
||||
this.recursionMarker = this.getAttribute("$recursionMarker","yes");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Collect string parameters
|
||||
*/
|
||||
TranscludeWidget.prototype.collectStringParameters = function() {
|
||||
var self = this;
|
||||
this.stringParametersByName = Object.create(null);
|
||||
if(!this.legacyMode) {
|
||||
$tw.utils.each(this.attributes,function(value,name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
if(name.charAt(1) === "$") {
|
||||
// Attributes starting $$ represent parameters starting with a single $
|
||||
name = name.slice(1);
|
||||
} else {
|
||||
// Attributes starting with a single $ are reserved for the widget
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.stringParametersByName[name] = value;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Collect slot value parameters
|
||||
*/
|
||||
TranscludeWidget.prototype.collectSlotFillParameters = function() {
|
||||
var self = this;
|
||||
this.slotFillParseTrees = Object.create(null);
|
||||
if(this.legacyMode) {
|
||||
this.slotFillParseTrees["ts-missing"] = this.parseTreeNode.children;
|
||||
} else {
|
||||
this.slotFillParseTrees["ts-raw"] = this.parseTreeNode.children;
|
||||
var noFillWidgetsFound = true,
|
||||
searchParseTreeNodes = function(nodes) {
|
||||
$tw.utils.each(nodes,function(node) {
|
||||
if(node.type === "fill") {
|
||||
if(node.attributes["$name"] && node.attributes["$name"].type === "string") {
|
||||
var slotValueName = node.attributes["$name"].value;
|
||||
self.slotFillParseTrees[slotValueName] = node.children || [];
|
||||
}
|
||||
noFillWidgetsFound = false;
|
||||
} else {
|
||||
searchParseTreeNodes(node.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
searchParseTreeNodes(this.parseTreeNode.children);
|
||||
if(noFillWidgetsFound) {
|
||||
this.slotFillParseTrees["ts-missing"] = this.parseTreeNode.children;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get transcluded parse tree nodes as an object {parser:,text:,type:}
|
||||
*/
|
||||
TranscludeWidget.prototype.getTransclusionTarget = function() {
|
||||
var self = this;
|
||||
// Determine whether we're being used in inline or block mode
|
||||
var parseAsInline = !this.parseTreeNode.isBlock;
|
||||
if(this.transcludeMode === "inline") {
|
||||
parseAsInline = true;
|
||||
} else if(this.transcludeMode === "block") {
|
||||
parseAsInline = false;
|
||||
}
|
||||
var parser = this.wiki.parseTextReference(
|
||||
var parser;
|
||||
// Get the parse tree
|
||||
if(this.transcludeVariable) {
|
||||
// Transcluding a variable
|
||||
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()}),
|
||||
srcVariable = variableInfo && variableInfo.srcVariable;
|
||||
if(srcVariable) {
|
||||
if(srcVariable.isFunctionDefinition) {
|
||||
// Function to return parameters by name or position
|
||||
var fnGetParam = function(name,index) {
|
||||
// Parameter names starting with dollar must be escaped to double dollars
|
||||
if(name.charAt(0) === "$") {
|
||||
name = "$" + name;
|
||||
}
|
||||
// Look for the parameter by name
|
||||
if(self.hasAttribute(name)) {
|
||||
return self.getAttribute(name);
|
||||
// Look for the parameter by index
|
||||
} else if(self.hasAttribute(index + "")) {
|
||||
return self.getAttribute(index + "");
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
result = this.evaluateVariable(this.transcludeVariable,{params: fnGetParam})[0] || "";
|
||||
parser = {
|
||||
tree: [{
|
||||
type: "text",
|
||||
text: result
|
||||
}],
|
||||
source: result,
|
||||
type: "text/vnd.tiddlywiki"
|
||||
};
|
||||
if(parseAsInline) {
|
||||
parser.tree[0] = {
|
||||
type: "text",
|
||||
text: result
|
||||
};
|
||||
} else {
|
||||
parser.tree[0] = {
|
||||
type: "element",
|
||||
tag: "p",
|
||||
children: [{
|
||||
type: "text",
|
||||
text: result
|
||||
}]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var cacheKey = (parseAsInline ? "inlineParser" : "blockParser") + (this.transcludeType || "");
|
||||
if(variableInfo.isCacheable && srcVariable[cacheKey]) {
|
||||
parser = srcVariable[cacheKey];
|
||||
} else {
|
||||
parser = this.wiki.parseText(this.transcludeType,variableInfo.text || "",{parseAsInline: parseAsInline, configTrimWhiteSpace: srcVariable.configTrimWhiteSpace});
|
||||
if(variableInfo.isCacheable) {
|
||||
srcVariable[cacheKey] = parser;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(parser) {
|
||||
// Add parameters widget for procedures and custom widgets
|
||||
if(srcVariable.isProcedureDefinition || srcVariable.isWidgetDefinition) {
|
||||
parser = {
|
||||
tree: [
|
||||
{
|
||||
type: "parameters",
|
||||
children: parser.tree
|
||||
}
|
||||
],
|
||||
source: parser.source,
|
||||
type: parser.type
|
||||
}
|
||||
$tw.utils.each(srcVariable.params,function(param) {
|
||||
var name = param.name;
|
||||
// Parameter names starting with dollar must be escaped to double dollars
|
||||
if(name.charAt(0) === "$") {
|
||||
name = "$" + name;
|
||||
}
|
||||
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],name,param["default"])
|
||||
});
|
||||
} else {
|
||||
// For macros and ordinary variables, wrap the parse tree in a vars widget assigning the parameters to variables named "__paramname__"
|
||||
parser = {
|
||||
tree: [
|
||||
{
|
||||
type: "vars",
|
||||
children: parser.tree
|
||||
}
|
||||
],
|
||||
source: parser.source,
|
||||
type: parser.type
|
||||
}
|
||||
$tw.utils.each(variableInfo.params,function(param) {
|
||||
$tw.utils.addAttributeToParseTreeNode(parser.tree[0],"__" + param.name + "__",param.value)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Transcluding a text reference
|
||||
parser = this.wiki.parseTextReference(
|
||||
this.transcludeTitle,
|
||||
this.transcludeField,
|
||||
this.transcludeIndex,
|
||||
{
|
||||
parseAsInline: parseAsInline,
|
||||
subTiddler: this.transcludeSubTiddler
|
||||
}),
|
||||
parseTreeNodes = parser ? parser.tree : this.parseTreeNode.children;
|
||||
this.sourceText = parser ? parser.source : null;
|
||||
this.parserType = parser? parser.type : null;
|
||||
// Set context variables for recursion detection
|
||||
var recursionMarker = this.makeRecursionMarker();
|
||||
if(this.recursionMarker === "yes") {
|
||||
this.setVariable("transclusion",recursionMarker);
|
||||
subTiddler: this.transcludeSubTiddler,
|
||||
defaultType: this.transcludeType
|
||||
});
|
||||
}
|
||||
// Set 'thisTiddler'
|
||||
this.setVariable("thisTiddler",this.transcludeTitle);
|
||||
// Check for recursion
|
||||
// Return the parse tree
|
||||
if(parser) {
|
||||
if(this.parentWidget && this.parentWidget.hasVariable("transclusion",recursionMarker)) {
|
||||
parseTreeNodes = [{type: "error", attributes: {
|
||||
"$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")}
|
||||
}}];
|
||||
return {
|
||||
parser: parser,
|
||||
parseTreeNodes: parser.tree,
|
||||
parseAsInline: parseAsInline,
|
||||
text: parser.source,
|
||||
type: parser.type
|
||||
};
|
||||
} else {
|
||||
// If there's no parse tree then return the missing slot value
|
||||
return {
|
||||
parser: null,
|
||||
parseTreeNodes: (this.slotFillParseTrees["ts-missing"] || []),
|
||||
parseAsInline: parseAsInline,
|
||||
text: null,
|
||||
type: null
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Fetch all the string parameters as an ordered array of {name:, value:} where the name is optional
|
||||
*/
|
||||
TranscludeWidget.prototype.getOrderedTransclusionParameters = function() {
|
||||
var result = [];
|
||||
// Collect the parameters
|
||||
for(var name in this.stringParametersByName) {
|
||||
var value = this.stringParametersByName[name];
|
||||
result.push({name: name, value: value});
|
||||
}
|
||||
// Sort numerical parameter names first
|
||||
result.sort(function(a,b) {
|
||||
var aIsNumeric = !isNaN(a.name),
|
||||
bIsNumeric = !isNaN(b.name);
|
||||
if(aIsNumeric && bIsNumeric) {
|
||||
return a.name - b.name;
|
||||
} else if(aIsNumeric) {
|
||||
return -1;
|
||||
} else if(bIsNumeric) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.name === b.name ? 0 : (a.name < b.name ? -1 : 1);
|
||||
}
|
||||
});
|
||||
// Remove names from numerical parameters
|
||||
$tw.utils.each(result,function(param,index) {
|
||||
if(!isNaN(param.name)) {
|
||||
delete param.name;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
/*
|
||||
Fetch the value of a parameter
|
||||
*/
|
||||
TranscludeWidget.prototype.getTransclusionParameter = function(name,index,defaultValue) {
|
||||
if(name in this.stringParametersByName) {
|
||||
return this.stringParametersByName[name];
|
||||
} else {
|
||||
var name = "" + index;
|
||||
if(name in this.stringParametersByName) {
|
||||
return this.stringParametersByName[name];
|
||||
}
|
||||
}
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets(parseTreeNodes);
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
/*
|
||||
Get one of the special parameters to be provided by the parameters widget
|
||||
*/
|
||||
TranscludeWidget.prototype.getTransclusionMetaParameters = function() {
|
||||
var self = this;
|
||||
return {
|
||||
"parseMode": function() {
|
||||
return self.parseAsInline ? "inline" : "block";
|
||||
},
|
||||
"parseTreeNodes": function() {
|
||||
return JSON.stringify(self.parseTreeNode.children || []);
|
||||
},
|
||||
"slotFillParseTreeNodes": function() {
|
||||
return JSON.stringify(self.slotFillParseTrees);
|
||||
},
|
||||
"params": function() {
|
||||
return JSON.stringify(self.stringParametersByName);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Fetch the value of a slot
|
||||
*/
|
||||
TranscludeWidget.prototype.getTransclusionSlotFill = function(name,defaultParseTreeNodes) {
|
||||
if(name && this.slotFillParseTrees[name] && this.slotFillParseTrees[name].length > 0) {
|
||||
return this.slotFillParseTrees[name];
|
||||
} else {
|
||||
return defaultParseTreeNodes || [];
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@ -101,6 +402,7 @@ TranscludeWidget.prototype.makeRecursionMarker = function() {
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.parserNeedsRefresh = function() {
|
||||
// Doesn't need to consider transcluded variables because a parent variable can't change once a widget has been created
|
||||
var parserInfo = this.wiki.getTextReferenceParserInfo(this.transcludeTitle,this.transcludeField,this.transcludeIndex,{subTiddler:this.transcludeSubTiddler});
|
||||
return (this.sourceText === undefined || parserInfo.sourceText !== this.sourceText || parserInfo.parserType !== this.parserType)
|
||||
};
|
||||
@ -110,7 +412,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
TranscludeWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(($tw.utils.count(changedAttributes) > 0) || (changedTiddlers[this.transcludeTitle] && this.parserNeedsRefresh())) {
|
||||
if(($tw.utils.count(changedAttributes) > 0) || (!this.transcludeVariable && changedTiddlers[this.transcludeTitle] && this.parserNeedsRefresh())) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
|
@ -41,10 +41,7 @@ Widget.prototype.initialise = function(parseTreeNode,options) {
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
this.wiki = options.wiki;
|
||||
this.parentWidget = options.parentWidget;
|
||||
this.variables = Object.create(null);
|
||||
if(this.parentWidget) {
|
||||
Object.setPrototypeOf(this.variables,this.parentWidget.variables);
|
||||
}
|
||||
this.variables = Object.create(this.parentWidget ? this.parentWidget.variables : null);
|
||||
this.document = options.document;
|
||||
this.attributes = {};
|
||||
this.children = [];
|
||||
@ -92,9 +89,22 @@ name: name of the variable
|
||||
value: value of the variable
|
||||
params: array of {name:, default:} for each parameter
|
||||
isMacroDefinition: true if the variable is set via a \define macro pragma (and hence should have variable substitution performed)
|
||||
options includes:
|
||||
isProcedureDefinition: true if the variable is set via a \procedure pragma (and hence should not have variable substitution performed)
|
||||
isFunctionDefinition: true if the variable is set via a \function pragma (and hence should not have variable substitution performed)
|
||||
isWidgetDefinition: true if the variable is set via a \widget pragma (and hence should not have variable substitution performed)
|
||||
*/
|
||||
Widget.prototype.setVariable = function(name,value,params,isMacroDefinition) {
|
||||
this.variables[name] = {value: value, params: params, isMacroDefinition: !!isMacroDefinition};
|
||||
Widget.prototype.setVariable = function(name,value,params,isMacroDefinition,options) {
|
||||
options = options || {};
|
||||
this.variables[name] = {
|
||||
value: value,
|
||||
params: params,
|
||||
isMacroDefinition: !!isMacroDefinition,
|
||||
isFunctionDefinition: !!options.isFunctionDefinition,
|
||||
isProcedureDefinition: !!options.isProcedureDefinition,
|
||||
isWidgetDefinition: !!options.isWidgetDefinition,
|
||||
configTrimWhiteSpace: !!options.configTrimWhiteSpace
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
@ -104,6 +114,7 @@ options: see below
|
||||
Options include
|
||||
params: array of {name:, value:} for each parameter
|
||||
defaultValue: default value if the variable is not defined
|
||||
allowSelfAssigned: if true, includes the current widget in the context chain instead of just the parent
|
||||
|
||||
Returns an object with the following fields:
|
||||
|
||||
@ -112,21 +123,27 @@ text: text of variable, with parameters properly substituted
|
||||
*/
|
||||
Widget.prototype.getVariableInfo = function(name,options) {
|
||||
options = options || {};
|
||||
var actualParams = options.params || [],
|
||||
parentWidget = this.parentWidget;
|
||||
var self = this,
|
||||
actualParams = options.params || [],
|
||||
variable;
|
||||
if(options.allowSelfAssigned) {
|
||||
variable = this.variables[name];
|
||||
} else {
|
||||
variable = this.parentWidget && this.parentWidget.variables[name];
|
||||
}
|
||||
// Check for the variable defined in the parent widget (or an ancestor in the prototype chain)
|
||||
if(parentWidget && name in parentWidget.variables) {
|
||||
var variable = parentWidget.variables[name],
|
||||
originalValue = variable.value,
|
||||
if(variable) {
|
||||
var originalValue = variable.value,
|
||||
value = originalValue,
|
||||
params = this.resolveVariableParameters(variable.params,actualParams);
|
||||
// Substitute any parameters specified in the definition
|
||||
$tw.utils.each(params,function(param) {
|
||||
value = $tw.utils.replaceString(value,new RegExp("\\$" + $tw.utils.escapeRegExp(param.name) + "\\$","mg"),param.value);
|
||||
});
|
||||
// Only substitute variable references if this variable was defined with the \define pragma
|
||||
params = [];
|
||||
// Only substitute parameter and variable references if this variable was defined with the \define pragma
|
||||
if(variable.isMacroDefinition) {
|
||||
value = this.substituteVariableReferences(value,options);
|
||||
params = self.resolveVariableParameters(variable.params,actualParams);
|
||||
// Substitute any parameters specified in the definition
|
||||
$tw.utils.each(params,function(param) {
|
||||
value = $tw.utils.replaceString(value,new RegExp("\\$" + $tw.utils.escapeRegExp(param.name) + "\\$","mg"),param.value);
|
||||
});
|
||||
value = self.substituteVariableReferences(value,options);
|
||||
}
|
||||
return {
|
||||
text: value,
|
||||
@ -136,8 +153,13 @@ Widget.prototype.getVariableInfo = function(name,options) {
|
||||
};
|
||||
}
|
||||
// If the variable doesn't exist in the parent widget then look for a macro module
|
||||
var text = this.evaluateMacroModule(name,actualParams);
|
||||
if(text === undefined) {
|
||||
text = options.defaultValue;
|
||||
}
|
||||
return {
|
||||
text: this.evaluateMacroModule(name,actualParams,options.defaultValue)
|
||||
text: text,
|
||||
srcVariable: {}
|
||||
};
|
||||
};
|
||||
|
||||
@ -148,6 +170,11 @@ Widget.prototype.getVariable = function(name,options) {
|
||||
return this.getVariableInfo(name,options).text;
|
||||
};
|
||||
|
||||
/*
|
||||
Maps actual parameters onto formal parameters, returning an array of {name:,value:} objects
|
||||
formalParams - Array of {name:,default:} (default value is optional)
|
||||
actualParams - Array of string values or {name:,value:} (name is optional)
|
||||
*/
|
||||
Widget.prototype.resolveVariableParameters = function(formalParams,actualParams) {
|
||||
formalParams = formalParams || [];
|
||||
actualParams = actualParams || [];
|
||||
@ -160,7 +187,7 @@ Widget.prototype.resolveVariableParameters = function(formalParams,actualParams)
|
||||
paramInfo = formalParams[p];
|
||||
paramValue = undefined;
|
||||
for(var m=0; m<actualParams.length; m++) {
|
||||
if(actualParams[m].name === paramInfo.name) {
|
||||
if(typeof actualParams[m] !== "string" && actualParams[m].name === paramInfo.name) {
|
||||
paramValue = actualParams[m].value;
|
||||
}
|
||||
}
|
||||
@ -169,7 +196,8 @@ Widget.prototype.resolveVariableParameters = function(formalParams,actualParams)
|
||||
nextAnonParameter++;
|
||||
}
|
||||
if(paramValue === undefined && nextAnonParameter < actualParams.length) {
|
||||
paramValue = actualParams[nextAnonParameter++].value;
|
||||
var param = actualParams[nextAnonParameter++];
|
||||
paramValue = typeof param === "string" ? param : param.value;
|
||||
}
|
||||
// If we've still not got a value, use the default, if any
|
||||
paramValue = paramValue || paramInfo["default"] || "";
|
||||
@ -263,12 +291,103 @@ Widget.prototype.getStateQualifier = function(name) {
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the current values of the attributes of the widget. Returns a hashmap of the names of the attributes that have changed
|
||||
Make a fake widget with specified variables, suitable for variable lookup in filters
|
||||
*/
|
||||
Widget.prototype.computeAttributes = function() {
|
||||
Widget.prototype.makeFakeWidgetWithVariables = function(variables) {
|
||||
var self = this;
|
||||
return {
|
||||
getVariable: function(name,opts) {
|
||||
if($tw.utils.hop(variables,name)) {
|
||||
return variables[name];
|
||||
} else {
|
||||
opts = opts || {};
|
||||
opts.variables = variables;
|
||||
return self.getVariable(name,opts);
|
||||
};
|
||||
},
|
||||
getVariableInfo: function(name,opts) {
|
||||
if($tw.utils.hop(variables,name)) {
|
||||
return {
|
||||
text: variables[name]
|
||||
};
|
||||
} else {
|
||||
opts = opts || {};
|
||||
opts.variables = variables;
|
||||
return self.getVariableInfo(name,opts);
|
||||
};
|
||||
},
|
||||
makeFakeWidgetWithVariables: self.makeFakeWidgetWithVariables,
|
||||
evaluateVariable: self.evaluateVariable,
|
||||
resolveVariableParameters: self.resolveVariableParameters,
|
||||
wiki: self.wiki
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Evaluate a variable and associated actual parameters and result the resulting array.
|
||||
The way that the variable is evaluated depends upon its type:
|
||||
* Functions are evaluated as parameterised filter strings
|
||||
* Macros are returned as plain text with substitution of parameters
|
||||
* Procedures and widgets are returned as plain text
|
||||
|
||||
Options are:
|
||||
params - the actual parameters – may be one of:
|
||||
* an array of values that may be an anonymous string value, or a {name:, value:} pair
|
||||
* a hashmap of {name: value} pairs
|
||||
* a function invoked with parameters (name,index) that returns a parameter value by name or position
|
||||
source - iterator for source tiddlers
|
||||
*/
|
||||
Widget.prototype.evaluateVariable = function(name,options) {
|
||||
options = options || {};
|
||||
var params = options.params || [];
|
||||
// Get the details of the variable (includes processing text substitution for macros
|
||||
var variableInfo = this.getVariableInfo(name,{params: params,defaultValue: ""});
|
||||
// Process function parameters
|
||||
var variables = Object.create(null);
|
||||
if(variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) {
|
||||
// Apply default parameter values
|
||||
$tw.utils.each(variableInfo.srcVariable.params,function(param,index) {
|
||||
if(param["default"]) {
|
||||
variables[param.name] = param["default"];
|
||||
}
|
||||
});
|
||||
if($tw.utils.isArray(params)) {
|
||||
// Parameters are an array of values or {name:, value:} pairs
|
||||
$tw.utils.each(this.resolveVariableParameters(variableInfo.srcVariable.params,params),function(param) {
|
||||
variables[param.name] = param.value;
|
||||
});
|
||||
} else if(typeof params === "function") {
|
||||
// Parameters are passed via a function
|
||||
$tw.utils.each(variableInfo.srcVariable.params,function(param,index) {
|
||||
variables[param.name] = params(param.name,index) || param["default"] || "";
|
||||
});
|
||||
} else {
|
||||
// Parameters are a hashmap
|
||||
$tw.utils.each(params,function(value,name) {
|
||||
variables[name] = value;
|
||||
});
|
||||
}
|
||||
return this.wiki.filterTiddlers(variableInfo.text,this.makeFakeWidgetWithVariables(variables),options.source);
|
||||
} else {
|
||||
return [variableInfo.text];
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the current values of the attributes of the widget. Returns a hashmap of the names of the attributes that have changed.
|
||||
Options include:
|
||||
filterFn: only include attributes where filterFn(name) returns true
|
||||
*/
|
||||
Widget.prototype.computeAttributes = function(options) {
|
||||
options = options || {};
|
||||
var changedAttributes = {},
|
||||
self = this;
|
||||
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
|
||||
if(options.filterFn) {
|
||||
if(!options.filterFn(name)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var value = self.computeAttribute(attribute);
|
||||
if(self.attributes[name] !== value) {
|
||||
self.attributes[name] = value;
|
||||
@ -279,13 +398,21 @@ Widget.prototype.computeAttributes = function() {
|
||||
};
|
||||
|
||||
Widget.prototype.computeAttribute = function(attribute) {
|
||||
var value;
|
||||
var self = this,
|
||||
value;
|
||||
if(attribute.type === "filtered") {
|
||||
value = this.wiki.filterTiddlers(attribute.filter,this)[0] || "";
|
||||
} else if(attribute.type === "indirect") {
|
||||
value = this.wiki.getTextReference(attribute.textReference,"",this.getVariable("currentTiddler"));
|
||||
} else if(attribute.type === "macro") {
|
||||
value = this.getVariable(attribute.value.name,{params: attribute.value.params});
|
||||
var variableInfo = this.getVariableInfo(attribute.value.name,{params: attribute.value.params});
|
||||
if(variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) {
|
||||
// It is a function definition. Go through each of the defined parameters, and make a variable with the value of the corresponding provided parameter
|
||||
var paramArray = this.resolveVariableParameters(variableInfo.srcVariable.params,attribute.value.params);
|
||||
value = this.evaluateVariable(attribute.value.name,{params: paramArray})[0] || "";
|
||||
} else {
|
||||
value = variableInfo.text;
|
||||
}
|
||||
} else { // String attribute
|
||||
value = attribute.value;
|
||||
}
|
||||
@ -413,7 +540,34 @@ options include:
|
||||
variables: optional hashmap of variables to wrap around the widget
|
||||
*/
|
||||
Widget.prototype.makeChildWidget = function(parseTreeNode,options) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
// Check whether this node type is defined by a custom widget definition
|
||||
var variableDefinitionName = "$" + parseTreeNode.type;
|
||||
if(this.variables[variableDefinitionName]) {
|
||||
var isOverrideable = function() {
|
||||
// Widget is overrideable if it has a double dollar user defined name, or if it is an existing JS widget and we're not in safe mode
|
||||
return parseTreeNode.type.charAt(0) === "$" || (!!self.widgetClasses[parseTreeNode.type] && !$tw.safeMode);
|
||||
};
|
||||
if(!parseTreeNode.isNotRemappable && isOverrideable()) {
|
||||
var variableInfo = this.getVariableInfo(variableDefinitionName,{allowSelfAssigned: true});
|
||||
if(variableInfo && variableInfo.srcVariable && variableInfo.srcVariable.value && variableInfo.srcVariable.isWidgetDefinition) {
|
||||
var newParseTreeNode = {
|
||||
type: "transclude",
|
||||
children: parseTreeNode.children,
|
||||
isBlock: parseTreeNode.isBlock
|
||||
};
|
||||
$tw.utils.addAttributeToParseTreeNode(newParseTreeNode,"$variable",variableDefinitionName);
|
||||
$tw.utils.each(parseTreeNode.attributes,function(attr,name) {
|
||||
// If the attribute starts with a dollar then add an extra dollar so that it doesn't clash with the $xxx attributes of transclude
|
||||
name = name.charAt(0) === "$" ? "$" + name : name;
|
||||
$tw.utils.addAttributeToParseTreeNode(newParseTreeNode,$tw.utils.extend({},attr,{name: name}));
|
||||
});
|
||||
parseTreeNode = newParseTreeNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get the widget class for this node type
|
||||
var WidgetClass = this.widgetClasses[parseTreeNode.type];
|
||||
if(!WidgetClass) {
|
||||
WidgetClass = this.widgetClasses.text;
|
||||
|
@ -988,7 +988,8 @@ exports.parseText = function(type,text,options) {
|
||||
return new Parser(type,text,{
|
||||
parseAsInline: options.parseAsInline,
|
||||
wiki: this,
|
||||
_canonical_uri: options._canonical_uri
|
||||
_canonical_uri: options._canonical_uri,
|
||||
configTrimWhiteSpace: options.configTrimWhiteSpace
|
||||
});
|
||||
};
|
||||
|
||||
@ -1028,10 +1029,11 @@ exports.parseTextReference = function(title,field,index,options) {
|
||||
};
|
||||
|
||||
exports.getTextReferenceParserInfo = function(title,field,index,options) {
|
||||
var tiddler,
|
||||
var defaultType = options.defaultType || "text/vnd.tiddlywiki",
|
||||
tiddler,
|
||||
parserInfo = {
|
||||
sourceText : null,
|
||||
parserType : "text/vnd.tiddlywiki"
|
||||
parserType : defaultType
|
||||
};
|
||||
if(options.subTiddler) {
|
||||
tiddler = this.getSubTiddler(title,options.subTiddler);
|
||||
@ -1077,19 +1079,20 @@ exports.makeWidget = function(parser,options) {
|
||||
children: []
|
||||
},
|
||||
currWidgetNode = widgetNode;
|
||||
// Create set variable widgets for each variable
|
||||
$tw.utils.each(options.variables,function(value,name) {
|
||||
var setVariableWidget = {
|
||||
type: "set",
|
||||
// Create let variable widget for variables
|
||||
if($tw.utils.count(options.variables) > 0) {
|
||||
var letVariableWidget = {
|
||||
type: "let",
|
||||
attributes: {
|
||||
name: {type: "string", value: name},
|
||||
value: {type: "string", value: value}
|
||||
},
|
||||
children: []
|
||||
};
|
||||
currWidgetNode.children = [setVariableWidget];
|
||||
currWidgetNode = setVariableWidget;
|
||||
});
|
||||
$tw.utils.each(options.variables,function(value,name) {
|
||||
$tw.utils.addAttributeToParseTreeNode(letVariableWidget,name,"" + value);
|
||||
});
|
||||
currWidgetNode.children = [letVariableWidget];
|
||||
currWidgetNode = letVariableWidget;
|
||||
}
|
||||
// Add in the supplied parse tree nodes
|
||||
currWidgetNode.children = parser ? parser.tree : [];
|
||||
// Create the widget
|
||||
|
@ -5,7 +5,10 @@ title: $:/core/save/all-external-js
|
||||
\define saveTiddlerFilter()
|
||||
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/core]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]] $(publishFilter)$
|
||||
\end
|
||||
|
||||
<!-- Important: core library is provided by serving URI encoded $:/core/templates/tiddlywiki5.js -->
|
||||
\define defaultCoreURL() %24%3A%2Fcore%2Ftemplates%2Ftiddlywiki5.js
|
||||
|
||||
<$let coreURL={{{ [[coreURL]is[variable]then<coreURL>else<defaultCoreURL>] }}}>
|
||||
{{$:/core/templates/tiddlywiki5-external-js.html}}
|
||||
</$let>
|
||||
|
48
core/ui/Components/VisibleTransclude.tid
Normal file
48
core/ui/Components/VisibleTransclude.tid
Normal file
@ -0,0 +1,48 @@
|
||||
title: $:/core/ui/VisibleTransclude
|
||||
|
||||
<!--
|
||||
Import this component to make all the child transclusions visible.
|
||||
|
||||
Block transclusions are shown in red, and inline transclusions are shown in green.
|
||||
-->
|
||||
\widget $transclude()
|
||||
<!-- Use a parameters widget so that we can access the `$params` data -->
|
||||
<$parameters tiddler="" $$tiddler="" mode="" $$mode="" $parseMode="@parseMode" $params="@params">
|
||||
<!-- Replicate the logic of the transclude widget to determine the output mode, and hence the tag and colour to use for output -->
|
||||
<$let
|
||||
mode={{{ [[$mode]is[variable]then<$mode>!is[blank]] :else[[mode]is[variable]then<mode>!is[blank]] :else[<@parseMode>] }}}
|
||||
outputTag={{{ [<mode>match[inline]then[span]else[div]] }}}
|
||||
outputColour={{{ [<mode>match[inline]then[green]else[red]] }}}
|
||||
>
|
||||
<!-- Use divs or spans according to the mode -->
|
||||
<$genesis $type=<<outputTag>> style="color:white;padding:4px;" style.background=<<outputColour>>>
|
||||
<$genesis $type=<<outputTag>> style="display: inline-block;">
|
||||
<div style="background:white;color:black;font-size: 12px;line-height:1.2;text-align:left;font-weight:normal;padding:4px;margin:4px;">
|
||||
<!-- Render the parameters to the transclusion -->
|
||||
<$list filter="[<@params>jsonindexes[]]" emptyMessage="(none)">
|
||||
<div>
|
||||
<$text text=<<currentTiddler>>/><$text text=": "/><$text text={{{ [<@params>jsonget<currentTiddler>] }}}/>
|
||||
</div>
|
||||
</$list>
|
||||
</div>
|
||||
</$genesis>
|
||||
<$genesis $type=<<outputTag>> style="background:white;color:black;padding:4px;">
|
||||
<!-- Look for a parameter starting with $ to determine if we are in legacy mode -->
|
||||
<$list filter="[<@params>jsonindexes[]] :filter[<currentTiddler>prefix[$]] +[limit[1]]" variable="ignore" emptyMessage="""
|
||||
<!-- Legacy mode: we render the transclusion without a dollar sign for recursionMarker and mode -->
|
||||
<$genesis $type="$transclude" $remappable="no" $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>]" recursionMarker="no" mode=<<mode>>>
|
||||
<!-- Reach back up to the grandparent transclusion to get the correct slot value -->
|
||||
<$slot $name="ts-raw" $depth="2"/>
|
||||
</$genesis>
|
||||
""">
|
||||
<!-- Non-legacy mode: we use dollar signs for the recursionMarker and mode -->
|
||||
<$genesis $type="$transclude" $remappable="no" $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>]" $$recursionMarker="no" $$mode=<<mode>>>
|
||||
<!-- Reach back up to the grandparent transclusion to get the correct slot fill value -->
|
||||
<$slot $name="ts-raw" $depth="2"/>
|
||||
</$genesis>
|
||||
</$list>
|
||||
</$genesis>
|
||||
</$genesis>
|
||||
</$let>
|
||||
</$parameters>
|
||||
\end
|
@ -6,7 +6,7 @@ description: {{$:/language/Buttons/NewHere/Hint}}
|
||||
\whitespace trim
|
||||
\define newHereActions()
|
||||
\whitespace trim
|
||||
<$set name="tags" filter="[<currentTiddler>] [{$:/config/NewTiddler/Tags}]">
|
||||
<$set name="tags" filter="[<currentTiddler>] [enlist{$:/config/NewTiddler/Tags}]">
|
||||
<$action-sendmessage $message="tm-new-tiddler" tags=<<tags>>/>
|
||||
</$set>
|
||||
\end
|
||||
|
@ -1,6 +1,6 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/library/v5.2.6/index.html
|
||||
url: https://tiddlywiki.com/library/v5.2.8/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}}
|
||||
|
||||
{{$:/language/OfficialPluginLibrary/Hint}}
|
||||
|
@ -60,4 +60,4 @@ code-body: yes
|
||||
</div>
|
||||
</$let>
|
||||
</$qualify>
|
||||
\end
|
||||
\end
|
@ -1,11 +1,11 @@
|
||||
created: 20140923173639039
|
||||
creator: pmario
|
||||
modified: 20140924155046340
|
||||
modified: 20230307080008193
|
||||
modifier: pmario
|
||||
title: TaskManagement
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
In dieser Edition sind folgende Task Management Varianten beschreiben:
|
||||
In dieser Edition sind folgende Task Management Varianten beschrieben:
|
||||
|
||||
<<list-links filter:"[tag[TaskManagement]]">>
|
||||
|
||||
|
@ -2,7 +2,7 @@ color: #37d011
|
||||
created: 20140923104300415
|
||||
creator: pmario
|
||||
icon: $:/core/images/done-button
|
||||
modified: 20140923105208878
|
||||
modified: 20230307080039831
|
||||
modifier: ChrisK
|
||||
tags: done
|
||||
title: done
|
||||
@ -12,5 +12,5 @@ Diese Tag wird verwendet um "Tasks" als erledigt zu markieren.
|
||||
|
||||
Siehe auch:
|
||||
|
||||
* [[Task Management]] .. Beispiel
|
||||
* [[Task Management|TaskManagement]] .. Beispiel
|
||||
* [[Tag Manager|$:/TagManager]] .. Zuweisung der Farben und Symbole
|
@ -0,0 +1,6 @@
|
||||
created: 20230307080413903
|
||||
modified: 20230307080417122
|
||||
title: Importieren von Tiddlern
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
https://tiddlywiki.com/#Importing%20Tiddlers
|
@ -1,11 +1,11 @@
|
||||
created: 20140918094051245
|
||||
creator: pmario
|
||||
modified: 20140918094948642
|
||||
modified: 20230307080301079
|
||||
modifier: pmario
|
||||
tags: Referenz
|
||||
title: Liste aller HowTo's
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
Hier finden Sie eine Auflistung aller HowTo's
|
||||
Hier finden Sie eine Auflistung aller ~HowTo's
|
||||
|
||||
<<list-links "[tag[howto]]">>
|
6
editions/de-AT/tiddlers/konzept/Tagging.tid
Normal file
6
editions/de-AT/tiddlers/konzept/Tagging.tid
Normal file
@ -0,0 +1,6 @@
|
||||
created: 20230307081437974
|
||||
modified: 20230307081439303
|
||||
title: Tagging
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
https://tiddlywiki.com/#Tagging
|
@ -0,0 +1,6 @@
|
||||
created: 20230307080103029
|
||||
modified: 20230307080103029
|
||||
title: $:/themes/tiddlywiki/vanilla/options/sidebarlayout
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
fluid-fixed
|
7
editions/de-AT/tiddlers/widgets/ListWidget.tid
Normal file
7
editions/de-AT/tiddlers/widgets/ListWidget.tid
Normal file
@ -0,0 +1,7 @@
|
||||
created: 20230307081923415
|
||||
modified: 20230307081953759
|
||||
tags: Widgets
|
||||
title: ListWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
https://tiddlywiki.com/#ListWidget
|
7
editions/de-AT/tiddlers/widgets/TranscludeWidget.tid
Normal file
7
editions/de-AT/tiddlers/widgets/TranscludeWidget.tid
Normal file
@ -0,0 +1,7 @@
|
||||
created: 20230307082002353
|
||||
modified: 20230307082023207
|
||||
tags: Widgets
|
||||
title: TranscludeWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
https://tiddlywiki.com/#TranscludeWidget
|
@ -1,7 +1,7 @@
|
||||
caption: Bilder
|
||||
created: 20131205160221762
|
||||
creator: pmario
|
||||
modified: 20140921170652909
|
||||
modified: 20230307081713229
|
||||
modifier: pmario
|
||||
tags: WikiText
|
||||
title: Bilder in WikiText
|
||||
@ -25,7 +25,7 @@ oder
|
||||
|
||||
Wenn die Bildquelle der Titel eines existierenden Tiddlers ist, dann wird dieser direkt angezeigt. Ansonsten wird die Quelle als URL angesehen und ein HTML `<img>` Element wird erzeugt. Das `src` Attribut wird auf die [[URL]] gesetzt.
|
||||
|
||||
Ein [[Tooltip]] kann ebenfalls angegeben werden:
|
||||
Ein Tooltip kann ebenfalls angegeben werden:
|
||||
|
||||
```
|
||||
[img[Ich bin der Tooltip text|Motovun Jack.jpg]]
|
||||
@ -33,7 +33,7 @@ Ein [[Tooltip]] kann ebenfalls angegeben werden:
|
||||
|
||||
[img width=100 [Ich bin der Tooltip text|Motovun Jack.jpg]]
|
||||
|
||||
Attribute wie zB: CSS Klassen oder die Höhe und Breite können ebenfalls angegeben werden.
|
||||
Attribute wie z.B: CSS Klassen oder die Höhe und Breite können ebenfalls angegeben werden.
|
||||
|
||||
```
|
||||
[img width=64 [Motovun Jack.jpg]]
|
||||
|
@ -1,7 +1,7 @@
|
||||
caption: Makros
|
||||
created: 20131205160746466
|
||||
creator: pmario
|
||||
modified: 20140922124415476
|
||||
modified: 20230307080132949
|
||||
modifier: ChrisK
|
||||
tags: WikiText
|
||||
title: Makros in WikiText
|
||||
@ -15,7 +15,7 @@ Hallo, Ich bin $name$ und lebe in $adresse$
|
||||
Hallo, Ich bin $name$ und würde gerne mal wieder nach $adresse$ fahren:)
|
||||
\end
|
||||
|
||||
!! Makros Definieren
|
||||
!! Makros definieren
|
||||
|
||||
!!! Für die Ungeduldigen
|
||||
|
||||
@ -76,7 +76,7 @@ Für einzeilige Makros kann die `\end` Markierung entfallen!
|
||||
|
||||
* Makros können mit dem ImportVariablesWidget importiert werden. (Für geübte Anwender)
|
||||
|
||||
!! Makros Verwenden
|
||||
!! Makros verwenden
|
||||
|
||||
```
|
||||
<<meinErstesMakro>>
|
||||
|
@ -0,0 +1,7 @@
|
||||
created: 20230307081757660
|
||||
modified: 20230307081814992
|
||||
tags: WikiText
|
||||
title: Transclusion in WikiText
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
https://tiddlywiki.com/#Transclusion%20in%20WikiText
|
@ -1,5 +0,0 @@
|
||||
created: 20201222190149806
|
||||
list: [[Release 5.1.23]]
|
||||
modified: 20201222190149806
|
||||
title: $:/StoryList
|
||||
type: text/vnd.tiddlywiki
|
83
editions/prerelease/tiddlers/Release 5.3.0.tid
Normal file
83
editions/prerelease/tiddlers/Release 5.3.0.tid
Normal file
@ -0,0 +1,83 @@
|
||||
caption: 5.3.0
|
||||
created: 20230419103154368
|
||||
modified: 20230419103154368
|
||||
tags: ReleaseNotes
|
||||
title: Release 5.3.0
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
//[[See GitHub for detailed change history of this release|https://github.com/Jermolene/TiddlyWiki5/compare/master...parameterised-transclusions]]//
|
||||
|
||||
! About v5.3.0
|
||||
|
||||
This pre-release introduces a number of significant improvements and new features related to some of TiddlyWiki's most fundamental components: macros, widgets, operators and transclusion.
|
||||
|
||||
! Introduction to v5.3.0
|
||||
|
||||
The motivation of these changes is to fix one of ~TiddlyWiki 5's early design flaws: the reliance on macros using textual substitution as the primary way to modularise and reuse wikitext and filters.
|
||||
|
||||
Experience has shown that while macros are a good match for a small number of tasks, they are brittle and error prone for many common operations. See [[Macro Pitfalls]] for a discussion of the problems that accompany this approach. Over the years we have introduced mitigations for the worst problems but these have come at a cost of increased complexity.
|
||||
|
||||
The changes in this release provide powerful new ways to achieve common tasks, and unlock completely new capabilities that were previously impossible in wikitext.
|
||||
|
||||
* [[Procedures]], which are essentially what macros should have been; they work in exactly the same way except that parameters are exposed as simple variables (without the double underscores) and no textual substitution takes place
|
||||
* [[Custom Widgets]], allowing the creation of widgets in wikitext, and the redefinition of built-in widgets
|
||||
* [[Functions]], a new way to encapsulate filter expressions with named parameters, including the ability to make custom filter operators
|
||||
* Parameterised [[Transclusions|Transclusion]], allowing strings and wikitext trees to be passed to transclusions
|
||||
|
||||
The approach taken by this release is to add new functionality by extending and augmenting the system without disturbing existing functionality. All of these changes are thus intended to be backwards compatible. While they represent a new field of opportunities for wikitext authors, it is possible for authors to ignore all these new features and continue to use ~TiddlyWiki 5 in the way that they have always done.
|
||||
|
||||
These changes lay the groundwork for macros and related features to be deprecated (which is the point at which users are advised not to use old features, and instead given clear pointers to the equivalent modern functionality).
|
||||
|
||||
The new transclusion architecture is not by itself sufficient to enable us to fully deprecate macros yet. To handle the remaining use cases we propose a new backtick quoted attribute format that allows for the substitution of variable values. See https://github.com/Jermolene/TiddlyWiki5/issues/6663 for details.
|
||||
|
||||
! Plugin Improvements
|
||||
|
||||
*
|
||||
|
||||
! Translation improvement
|
||||
|
||||
Improvements to the following translations:
|
||||
|
||||
*
|
||||
|
||||
! Accessibility Improvements
|
||||
|
||||
*
|
||||
|
||||
! Usability Improvements
|
||||
|
||||
*
|
||||
|
||||
! Widget Improvements
|
||||
|
||||
*
|
||||
|
||||
! Filter improvements
|
||||
|
||||
*
|
||||
|
||||
! Hackability Improvements
|
||||
|
||||
*
|
||||
|
||||
! Bug Fixes
|
||||
|
||||
*
|
||||
|
||||
! Developer Improvements
|
||||
|
||||
*
|
||||
|
||||
! Node.js Improvements
|
||||
|
||||
*
|
||||
|
||||
! Performance Improvements
|
||||
|
||||
*
|
||||
! Acknowledgements
|
||||
|
||||
[[@Jermolene|https://github.com/Jermolene]] would like to thank the contributors to this release who have generously given their time to help improve TiddlyWiki:
|
||||
|
||||
<<.contributors """
|
||||
""">>
|
@ -1,6 +1,6 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/prerelease/library/v5.2.6/index.html
|
||||
url: https://tiddlywiki.com/prerelease/library/v5.2.8/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}} (Prerelease)
|
||||
|
||||
The prerelease version of the official ~TiddlyWiki plugin library at tiddlywiki.com. Plugins, themes and language packs are maintained by the core team.
|
||||
|
@ -0,0 +1,7 @@
|
||||
created: 20230314153132081
|
||||
modified: 20230314153243008
|
||||
title: $:/DefaultTiddlers
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
GettingStarted
|
||||
[[Using the external JavaScript template]]
|
@ -0,0 +1,4 @@
|
||||
title: $:/config/SaveWikiButton/Filename
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
external-<<version>>.html
|
8
editions/server-external-js/tiddlers/external/tiddlywiki.files
vendored
Normal file
8
editions/server-external-js/tiddlers/external/tiddlywiki.files
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"tiddlers": [
|
||||
{
|
||||
"file": "../../../tw5.com/tiddlers/webserver/Using the external JavaScript template.tid",
|
||||
"isTiddlerFile": true
|
||||
}
|
||||
]
|
||||
}
|
@ -2,8 +2,7 @@
|
||||
"description": "Client-server edition with external tiddlywiki.js",
|
||||
"plugins": [
|
||||
"tiddlywiki/tiddlyweb",
|
||||
"tiddlywiki/filesystem",
|
||||
"tiddlywiki/highlight"
|
||||
"tiddlywiki/filesystem"
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
@ -13,7 +12,7 @@
|
||||
"listen": [
|
||||
"--listen","root-tiddler=$:/core/save/all-external-js","use-browser-cache=yes"],
|
||||
"index": [
|
||||
"--render","$:/core/save/offline-external-js","index.html","text/plain",
|
||||
"--render","$:/core/save/offline-external-js","[[external-]addsuffix<version>addsuffix[.html]]","text/plain",
|
||||
"--render","$:/core/templates/tiddlywiki5.js","[[tiddlywikicore-]addsuffix<version>addsuffix[.js]]","text/plain"],
|
||||
"static": [
|
||||
"--render","$:/core/templates/static.template.html","static.html","text/plain",
|
||||
|
@ -0,0 +1,24 @@
|
||||
title: CustomOperators/NestedParameterised
|
||||
description: Nested parameterised custom operator usage
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\function .dividebysomething(first:ignored,factor:0.5)
|
||||
[divide[2]multiply<factor>]
|
||||
\end
|
||||
|
||||
\function .multiplebysomething(first:ignored,factor:2)
|
||||
[multiply[2].dividebysomething[],<factor>]
|
||||
\end
|
||||
|
||||
<$text text={{{ [[123].multiplebysomething[]] }}}/>
|
||||
-
|
||||
<$text text={{{ [[123].multiplebysomething[x],[4]] }}}/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>246-492</p>
|
@ -0,0 +1,24 @@
|
||||
title: CustomOperators/Parameterised
|
||||
description: Parameterised custom operator usage
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\function .multiplybysomething(first:ignored,factor:2)
|
||||
[multiply[2]multiply<factor>]
|
||||
\end
|
||||
|
||||
<$text text={{{ [[123].multiplybysomething[]] }}}/>
|
||||
-
|
||||
<$text text={{{ [[123].multiplybysomething[x],[4]] }}}/>
|
||||
|
|
||||
<$text text={{{ [[123]function[.multiplybysomething]] }}}/>
|
||||
-
|
||||
<$text text={{{ [[123]function[.multiplybysomething],[x],[4]] }}}/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>492-984|492-984</p>
|
@ -0,0 +1,21 @@
|
||||
title: CustomOperators/Simple
|
||||
description: Simple custom operator usage
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\function .multiplybytwo()
|
||||
[multiply[2]]
|
||||
\end
|
||||
|
||||
<$text text={{{ [[123].multiplybytwo[]] }}}/>
|
||||
|
|
||||
<$text text={{{ [[123]function[.multiplybytwo]] }}}/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>246|246</p>
|
@ -0,0 +1,28 @@
|
||||
title: Filters/DiffMergePatch1
|
||||
description: Tests for diff-merge-patch derived operators
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\define text1()
|
||||
the cat sat on the mat
|
||||
\end
|
||||
|
||||
\define text2()
|
||||
the hat saw in every category
|
||||
\end
|
||||
|
||||
<$text text={{{ [<text1>makepatches<text2>] }}}/>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>@@ -1,22 +1,29 @@
|
||||
the
|
||||
-c
|
||||
+h
|
||||
at sa
|
||||
-t on the mat
|
||||
+w in every category
|
||||
</p>
|
@ -0,0 +1,25 @@
|
||||
title: Filters/DiffMergePatch2
|
||||
description: Tests for diff-merge-patch derived operators
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\define text1()
|
||||
the cat sat on the mat
|
||||
\end
|
||||
|
||||
\define text2()
|
||||
the hat saw in every category
|
||||
\end
|
||||
|
||||
<$let patches={{{ [<text1>makepatches<text2>] }}}>
|
||||
|
||||
<$text text={{{ [<text1>applypatches<patches>] }}}/>
|
||||
|
||||
</$let>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
the hat saw in every category
|
@ -0,0 +1,22 @@
|
||||
title: Filters/DiffMergePatch3
|
||||
description: Tests for diff-merge-patch derived operators
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\define text1()
|
||||
the cat sat on the mat
|
||||
\end
|
||||
|
||||
\define patches()
|
||||
**NOT A VALID PATCH**
|
||||
\end
|
||||
|
||||
<$text text={{{ [<text1>applypatches<patches>] }}}/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
the cat sat on the mat
|
@ -0,0 +1,24 @@
|
||||
title: Functions/FunctionAttributes
|
||||
description: Attributes specified as function invocations
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\function .dividebysomething(factor:0.5)
|
||||
[divide<factor>]
|
||||
\end
|
||||
|
||||
\function multiplebysomething(first:ignored,factor:2)
|
||||
[<factor>multiply[2].dividebysomething[0.25]]
|
||||
\end
|
||||
|
||||
<$text text=<<multiplebysomething>>/>
|
||||
|
|
||||
<$text text=<<multiplebysomething "nothing" "4">>/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>16|32</p>
|
@ -0,0 +1,24 @@
|
||||
title: Functions/FunctionOperator
|
||||
description: Calling a function via the function operator
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\function .dividebysomething(factor:0.5)
|
||||
[divide<factor>]
|
||||
\end
|
||||
|
||||
\function multiplebysomething(first:ignored,factor:2)
|
||||
[multiply<factor>multiply[2].dividebysomething[0.25]]
|
||||
\end
|
||||
|
||||
<$text text={{{ [[4]function[multiplebysomething]] }}}/>
|
||||
|
|
||||
<$text text={{{ [[6]function[multiplebysomething],[ignored],[4]] }}}/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>64|192</p>
|
@ -0,0 +1,15 @@
|
||||
title: Functions/MissingFunction
|
||||
description: Calling a missing function via the function operator
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
<$text text={{{ [[23]function[missing]] }}}/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
23
|
@ -0,0 +1,18 @@
|
||||
title: Functions/RunawayRecursiveFunctions
|
||||
description: Runaway recursive functions
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\function .buffalo(p)
|
||||
[.buffalo<p>]
|
||||
\end
|
||||
|
||||
<$text text=<<.buffalo 8>>/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
/**-- Excessive filter recursion --**/
|
@ -0,0 +1,22 @@
|
||||
title: Functions/UndefinedParameters
|
||||
description: Undefined function parameters
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\function greet(who)
|
||||
[[hello ]addsuffix<who>]
|
||||
\end
|
||||
|
||||
<$text text={{{[function[greet],[world]]}}}/>
|
||||
|
||||
<<greet world>>
|
||||
|
||||
<$text text={{{[function[greet]]}}}/>
|
||||
|
||||
<<greet>>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
hello world<p>hello world</p>hello <p>hello </p>
|
@ -0,0 +1,36 @@
|
||||
title: Functions/WikifiedFunctions
|
||||
description: Wikified functions
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\function fn-buffalo(param)
|
||||
[<param>addsuffix[ with a ''buffalo'']]
|
||||
\end
|
||||
|
||||
\procedure proc-buffalo(param)
|
||||
<<param>> with a ''buffalo''
|
||||
\end
|
||||
|
||||
\define macro-buffalo(param)
|
||||
$param$ with a ''buffalo''
|
||||
\end
|
||||
|
||||
<<fn-buffalo "Going to lunch">>
|
||||
|
||||
<<proc-buffalo "Going to breakfast">>
|
||||
|
||||
<<macro-buffalo "Going to dinner">>
|
||||
|
||||
<$transclude $variable="fn-buffalo" param="Going to lunch" $output="text/plain"/>
|
||||
|
||||
<$transclude $variable="proc-buffalo" param="Going to breakfast" $output="text/plain"/>
|
||||
|
||||
<$transclude $variable="macro-buffalo" param="Going to dinner" $output="text/plain"/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>Going to lunch with a ''buffalo''</p><p>Going to breakfastwith a<strong>buffalo</strong></p><p>Going to dinner with a <strong>buffalo</strong></p>Going to lunch with a buffalo with a buffaloGoing to dinner with a buffalo
|
@ -0,0 +1,31 @@
|
||||
title: Genesis/RedefineLet
|
||||
description: Using the genesis widget to override the let widget
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\widget $let()
|
||||
\whitespace trim
|
||||
<$parameters $params="@params">
|
||||
<$setmultiplevariables $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>addprefix[--]addsuffix[--]]">
|
||||
<$slot $name="ts-raw"/>
|
||||
</$setmultiplevariables>
|
||||
</$parameters>
|
||||
\end
|
||||
<$let
|
||||
one="Elephant"
|
||||
$two="Kangaroo"
|
||||
$$three="Giraffe"
|
||||
>
|
||||
(<$text text=<<one>>/>)
|
||||
(<$text text=<<$two>>/>)
|
||||
(<$text text=<<$$three>>/>)
|
||||
</$let>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>(--Elephant--)
|
||||
(--Kangaroo--)
|
||||
(--Giraffe--)</p>
|
@ -0,0 +1,22 @@
|
||||
title: Macros/TrailingNewlines
|
||||
description: Trailing newlines in macros must not be dropped
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\define inner()
|
||||
Paragraph 1
|
||||
|
||||
Paragraph 2
|
||||
\end
|
||||
\define outer()
|
||||
<$macrocall $name=inner />
|
||||
|
||||
\end
|
||||
<<outer>>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>Paragraph 1</p><p>Paragraph 2</p>
|
20
editions/test/tiddlers/tests/data/procedures/Nested.tid
Normal file
20
editions/test/tiddlers/tests/data/procedures/Nested.tid
Normal file
@ -0,0 +1,20 @@
|
||||
title: Procedures/Nested
|
||||
description: Nested Procedures
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\procedure alpha(x)
|
||||
\procedure beta(y)
|
||||
<$text text=<<y>>/>
|
||||
\end beta
|
||||
<$transclude $variable="beta" y={{{ [<x>addprefix<x>] }}}/>
|
||||
\end alpha
|
||||
|
||||
<<alpha "Elephant">>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>ElephantElephant</p>
|
@ -0,0 +1,27 @@
|
||||
title: Transclude/CustomWidget/ActionWidget
|
||||
description: Custom widget definition
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$transclude $tiddler='Result'>
|
||||
</$transclude>
|
||||
+
|
||||
title: Actions
|
||||
|
||||
\whitespace trim
|
||||
<!-- Define the <$$action-mywidget> widget by defining a transcludable variable with that name -->
|
||||
\widget $$action-mywidget(one:'Jaguar')
|
||||
\whitespace trim
|
||||
<$action-setfield $tiddler="Result" $field="text" $value=<<one>>/>
|
||||
\end
|
||||
|
||||
<$$action-mywidget one="Dingo">
|
||||
Crocodile
|
||||
</$$action-mywidget>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>Dingo</p>
|
@ -0,0 +1,26 @@
|
||||
title: Transclude/CustomWidget/Fail
|
||||
description: Custom widget failed definition
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<!-- Attempt to define the <$non-existent-widget> widget by defining a transcludable variable with that name -->
|
||||
\widget $non-existent-widget(one:'Jaguar')
|
||||
\whitespace trim
|
||||
<$text text=<<one>>/>
|
||||
<$slot $name="ts-raw">
|
||||
Whale
|
||||
</$slot>
|
||||
\end
|
||||
<$non-existent-widget one="Dingo">
|
||||
Crocodile
|
||||
</$non-existent-widget>
|
||||
<$non-existent-widget one="BumbleBee">
|
||||
Squirrel
|
||||
</$non-existent-widget>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>Undefined widget 'non-existent-widget'Undefined widget 'non-existent-widget'</p>
|
@ -0,0 +1,29 @@
|
||||
title: CustomWidget-Override-Codeblock
|
||||
description: Usage of genesis widget with attributes starting with dollar signs
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\import Definition
|
||||
<$codeblock code="Kangaroo"/>
|
||||
<$codeblock code={{Subject}}/>
|
||||
<$let test="Tiger">
|
||||
<$codeblock code=<<test>>/>
|
||||
</$let>
|
||||
+
|
||||
title: Definition
|
||||
|
||||
\whitespace trim
|
||||
\widget $codeblock(code)
|
||||
<$genesis $type="$codeblock" $remappable="no" code={{{ [<code>addprefix[£]addsuffix[@]] }}}/>
|
||||
\end
|
||||
+
|
||||
title: Subject
|
||||
|
||||
Python
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><pre><code>£Kangaroo@</code></pre><pre><code>£Python@</code></pre><pre><code>£Tiger@</code></pre></p>
|
@ -0,0 +1,33 @@
|
||||
title: Transclude/CustomWidget/OverrideTransclude
|
||||
description: Custom widget definition attempting to override transclude
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$transclude $tiddler='TiddlerOne' one='Ferret'>
|
||||
</$transclude>
|
||||
+
|
||||
title: TiddlerZero
|
||||
|
||||
Antelope
|
||||
+
|
||||
title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
<!-- Redefine the <$transclude> widget by defining a transcludable variable with that name -->
|
||||
\widget $transclude(one:'Jaguar')
|
||||
\whitespace trim
|
||||
<$text text=<<one>>/>
|
||||
<$slot $name="body">
|
||||
Whale
|
||||
</$slot>
|
||||
\end
|
||||
<$genesis $type="$transclude" $remappable="no" $$tiddler="TiddlerZero">
|
||||
Crocodile
|
||||
</$genesis>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>Antelope</p>
|
@ -0,0 +1,33 @@
|
||||
title: Transclude/CustomWidget/Simple
|
||||
description: Custom widget definition
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$transclude $tiddler='TiddlerOne' one='Ferret'>
|
||||
</$transclude>
|
||||
+
|
||||
title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
<!-- Define the <$$mywidget> widget by defining a transcludable variable with that name -->
|
||||
\widget $$mywidget(one:'Jaguar')
|
||||
\whitespace trim
|
||||
<$text text=<<one>>/>
|
||||
<$slot $name="ts-raw">
|
||||
Whale
|
||||
</$slot>
|
||||
\end
|
||||
<$$mywidget one="Dingo">
|
||||
Crocodile
|
||||
</$$mywidget>
|
||||
<$$mywidget one="BumbleBee">
|
||||
Squirrel
|
||||
</$$mywidget>
|
||||
<$$mywidget/>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>DingoCrocodileBumbleBeeSquirrelJaguarWhale</p>
|
@ -0,0 +1,20 @@
|
||||
title: CustomWidget/Slotted/Empty
|
||||
description: Custom widget with empty slotted values
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\widget $$mywidget()
|
||||
<$slot $name=ts-raw>the body is empty</$slot>
|
||||
\end
|
||||
|
||||
#<$$mywidget/>
|
||||
#<$$mywidget></$$mywidget>
|
||||
#<$$mywidget>the body is not empty</$$mywidget>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<ol><li>the body is empty</li><li>the body is empty</li><li>the body is not empty</li></ol>
|
@ -0,0 +1,27 @@
|
||||
title: Transclude/CustomWidget/Slotted
|
||||
description: Custom widget definition
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\widget $$mywidget(one:'Jaguar')
|
||||
\whitespace trim
|
||||
<$text text=<<one>>/>
|
||||
<$slot $name="ts-stuff">
|
||||
Whale
|
||||
</$slot>
|
||||
\end
|
||||
<$$mywidget one="Dingo">
|
||||
<$fill $name="ts-stuff">
|
||||
Crocodile
|
||||
</$fill>
|
||||
</$$mywidget>
|
||||
<$$mywidget one="BumbleBee">
|
||||
Squirrel
|
||||
</$$mywidget>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>DingoCrocodileBumbleBeeWhale</p>
|
@ -0,0 +1,27 @@
|
||||
title: Transclude/CustomWidget/TextWidgetOverride
|
||||
description: Custom widget definition redefining the text widget
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$transclude $tiddler='TiddlerOne'>
|
||||
</$transclude>
|
||||
+
|
||||
title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
<!-- Redefining the text widget only works when it is explicitly invoked with the <$text> syntax, and not implicitly via typed text -->
|
||||
\widget $text(text:'Jaguar')
|
||||
\whitespace trim
|
||||
<$genesis $type="$text" $remappable="no" text={{{ [<text>addprefix[≤]addsuffix[≥]] }}}/>
|
||||
\end
|
||||
|
||||
<$text text="Dingo"/>
|
||||
|
||||
Crocodile
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>≤Dingo≥≤Jaguar≥</p>
|
@ -0,0 +1,31 @@
|
||||
title: Transclude/CustomWidget/TextWidgetOverrideWithSlot
|
||||
description: Custom widget definition redefining the text widget
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$transclude $tiddler='TiddlerOne'>
|
||||
</$transclude>
|
||||
+
|
||||
title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
<!-- Redefine the <$text> widget by defining a transcludable variable with that name -->
|
||||
\widget $text(text:'Jaguar')
|
||||
\whitespace trim
|
||||
<$genesis $type="$text" $remappable="no" text=<<text>>/>
|
||||
<$set name="$text" value="">
|
||||
<$slot $name="ts-raw">
|
||||
Whale
|
||||
</$slot>
|
||||
</$set>
|
||||
\end
|
||||
<$text text="Dingo">
|
||||
Crocodile
|
||||
</$text>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>DingoCrocodile</p>
|
@ -0,0 +1,31 @@
|
||||
title: CustomWidget-Unoverride-Codeblock
|
||||
description: Usage of genesis widget with attributes starting with dollar signs, and unoverriding a core widget
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\import Definition
|
||||
<$let $codeblock="">
|
||||
<$codeblock code="Kangaroo"/>
|
||||
<$codeblock code={{Subject}}/>
|
||||
<$let test="Tiger">
|
||||
<$codeblock code=<<test>>/>
|
||||
</$let>
|
||||
</$let>
|
||||
+
|
||||
title: Definition
|
||||
|
||||
\whitespace trim
|
||||
\widget $codeblock(code)
|
||||
<$genesis $type="codeblock" $remappable="no" code={{{ [<code>addprefix[£]addsuffix[@]] }}}/>
|
||||
\end
|
||||
+
|
||||
title: Subject
|
||||
|
||||
Python
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><pre><code>Kangaroo</code></pre><pre><code>Python</code></pre><pre><code>Tiger</code></pre></p>
|
@ -0,0 +1,29 @@
|
||||
title: Transclude/CustomWidget/VariableAttribute
|
||||
description: Custom widget definition using an attribute called $variable
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$transclude $tiddler='TiddlerOne' one='Ferret'>
|
||||
</$transclude>
|
||||
+
|
||||
title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
<!-- Redefine the <$$mywidget> widget by defining a transcludable variable with that name -->
|
||||
\widget $$mywidget($variable:'Jaguar')
|
||||
\whitespace trim
|
||||
<$text text=<<$variable>>/>
|
||||
<$slot $name="ts-raw">
|
||||
Whale
|
||||
</$slot>
|
||||
\end
|
||||
<$$mywidget $variable="Dingo">
|
||||
Crocodile
|
||||
</$$mywidget>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>DingoCrocodile</p>
|
@ -0,0 +1,17 @@
|
||||
title: Transclude/Macro/JavaScript
|
||||
description: Transcluding a javascript macro
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
<<makedatauri text:"Wildebeest" type:"text/plain">>
|
||||
|
||||
<$macrocall $name="makedatauri" text="Wildebeest" type="text/plain"/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><a class="tc-tiddlylink-external" href="data:text/plain,Wildebeest" rel="noopener noreferrer" target="_blank">data:text/plain,Wildebeest</a></p><p><a class="tc-tiddlylink-external" href="data:text/plain,Wildebeest" rel="noopener noreferrer" target="_blank">data:text/plain,Wildebeest</a></p>
|
17
editions/test/tiddlers/tests/data/transclude/Macro-Plain.tid
Normal file
17
editions/test/tiddlers/tests/data/transclude/Macro-Plain.tid
Normal file
@ -0,0 +1,17 @@
|
||||
title: Transclude/Macro/Plain
|
||||
description: Transcluding a macro as plain text
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$let currentTab="Jeremy">
|
||||
<$macrocall $name="currentTab" $type="text/plain" $output="text/plain"/>
|
||||
|
|
||||
<$transclude $variable="currentTab" $type="text/plain" $output="text/plain"/>
|
||||
</$let>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>Jeremy|Jeremy</p>
|
@ -0,0 +1,26 @@
|
||||
title: Transclude/Macro/Simple
|
||||
description: Transcluding a macro
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\define mamacro(one:"red",two:"green")
|
||||
It is $one$ and $two$ or <<__one__>> and <<__two__>>.
|
||||
\end
|
||||
|
||||
<$macrocall $name="mamacro"/>
|
||||
|
||||
<$transclude $variable="mamacro"/>
|
||||
|
||||
<$transclude $variable="mamacro" one="orange"/>
|
||||
|
||||
<$transclude $variable="mamacro" 0="pink"/>
|
||||
|
||||
<$transclude $variable="mamacro" one="purple" 1="pink"/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>It is red and green or red and green.</p><p>It is red and green or red and green.</p><p>It is orange and green or orange and green.</p><p>It is pink and green or pink and green.</p><p>It is purple and pink or purple and pink.</p>
|
@ -0,0 +1,48 @@
|
||||
title: Transclude/MissingTarget
|
||||
description: Transcluding a missing target
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$transclude $tiddler='TiddlerOne' one='Ferret'>
|
||||
<$parameters one='Ferret'>
|
||||
Badger
|
||||
<$text text=<<one>>/>
|
||||
</$parameters>
|
||||
</$transclude>
|
||||
<$transclude $tiddler='TiddlerOne' one='Ferret'>
|
||||
<$fill $name="ts-missing">
|
||||
<$parameters one='Ferret'>
|
||||
Badger
|
||||
<$text text=<<one>>/>
|
||||
</$parameters>
|
||||
</$fill>
|
||||
</$transclude>
|
||||
<$transclude $tiddler='MissingTiddler' one='Ferret'>
|
||||
<$parameters one='Ferret'>
|
||||
Badger
|
||||
<$text text=<<one>>/>
|
||||
</$parameters>
|
||||
</$transclude>
|
||||
<$transclude $tiddler='MissingTiddler' one='Ferret'>
|
||||
<$fill $name="ts-missing">
|
||||
<$parameters one='Ferret'>
|
||||
Badger
|
||||
<$text text=<<one>>/>
|
||||
</$parameters>
|
||||
</$fill>
|
||||
</$transclude>
|
||||
+
|
||||
title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
<$parameters one='Kangaroo'>
|
||||
Piranha
|
||||
<$text text=<<one>>/>
|
||||
</$parameters>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>PiranhaFerretPiranhaFerretBadgerFerretBadgerFerret</p>
|
@ -0,0 +1,34 @@
|
||||
title: Transclude/Parameterised/Depth
|
||||
description: Parameterised transclusion using the $depth attribute
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$transclude $tiddler='TiddlerOne' one='Ferret'/>
|
||||
|
|
||||
<$transclude $tiddler='TiddlerOne'/>
|
||||
|
|
||||
<$transclude $tiddler='TiddlerOne' one='Ferret' $$two="Osprey"/>
|
||||
|
|
||||
<$transclude $tiddler='TiddlerOne' $$two="Falcon"/>
|
||||
+
|
||||
title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
{{TiddlerTwo}}
|
||||
+
|
||||
title: TiddlerTwo
|
||||
|
||||
\whitespace trim
|
||||
<$parameters one='Jaguar' $$two='Piranha' $depth="2">
|
||||
<$text text=<<one>>/>:<$text text=<<$two>>/>
|
||||
</$parameters>
|
||||
<$parameters one='Leopard' $$two='Coelacanth'>
|
||||
(<$text text=<<one>>/>|<$text text=<<$two>>/>)
|
||||
</$parameters>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>Ferret:Piranha(Leopard|Coelacanth)|Jaguar:Piranha(Leopard|Coelacanth)|Ferret:Osprey(Leopard|Coelacanth)|Jaguar:Falcon(Leopard|Coelacanth)</p>
|
@ -0,0 +1,29 @@
|
||||
title: Transclude/Parameterised/Mode
|
||||
description: Parameterised transclusion using the $parseMode attribute
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
<$transclude $tiddler='TiddlerOne' one='Ferret'>
|
||||
|
||||
This is a block
|
||||
|
||||
</$transclude>
|
||||
|
||||
<$transclude $tiddler='TiddlerOne'>
|
||||
This is inline
|
||||
</$transclude>
|
||||
+
|
||||
title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
<$parameters $parseMode="@parseMode">
|
||||
<$text text=<<@parseMode>>/>
|
||||
</$parameters>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>block</p><p>inline</p>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user