mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-08-08 06:43:49 +00:00
Merge remote-tracking branch 'origin/master' into feature/cbr/load-defer
This commit is contained in:
commit
388824e26e
@ -1,6 +1,3 @@
|
|||||||
title: $:/boot/boot.css
|
|
||||||
type: text/css
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Basic styles used before we boot up the parsing engine
|
Basic styles used before we boot up the parsing engine
|
||||||
*/
|
*/
|
47
boot/boot.js
47
boot/boot.js
@ -142,15 +142,15 @@ $tw.utils.each = function(object,callback) {
|
|||||||
var next,f,length;
|
var next,f,length;
|
||||||
if(object) {
|
if(object) {
|
||||||
if(Object.prototype.toString.call(object) == "[object Array]") {
|
if(Object.prototype.toString.call(object) == "[object Array]") {
|
||||||
for (f=0, length=object.length; f<length; f++) {
|
for(f=0, length=object.length; f<length; f++) {
|
||||||
next = callback(object[f],f,object);
|
next = callback(object[f],f,object);
|
||||||
if(next === false) {
|
if(next === false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var keys = Object.keys(object);
|
var keys = Object.keys(object);
|
||||||
for (f=0, length=keys.length; f<length; f++) {
|
for(f=0, length=keys.length; f<length; f++) {
|
||||||
var key = keys[f];
|
var key = keys[f];
|
||||||
next = callback(object[key],key,object);
|
next = callback(object[key],key,object);
|
||||||
if(next === false) {
|
if(next === false) {
|
||||||
@ -275,7 +275,7 @@ Extend an object with the properties from a list of source objects
|
|||||||
$tw.utils.extend = function(object /*, sourceObjectList */) {
|
$tw.utils.extend = function(object /*, sourceObjectList */) {
|
||||||
$tw.utils.each(Array.prototype.slice.call(arguments,1),function(source) {
|
$tw.utils.each(Array.prototype.slice.call(arguments,1),function(source) {
|
||||||
if(source) {
|
if(source) {
|
||||||
for (var p in source) {
|
for(var p in source) {
|
||||||
object[p] = source[p];
|
object[p] = source[p];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,7 +289,7 @@ Fill in any null or undefined properties of an object with the properties from a
|
|||||||
$tw.utils.deepDefaults = function(object /*, sourceObjectList */) {
|
$tw.utils.deepDefaults = function(object /*, sourceObjectList */) {
|
||||||
$tw.utils.each(Array.prototype.slice.call(arguments,1),function(source) {
|
$tw.utils.each(Array.prototype.slice.call(arguments,1),function(source) {
|
||||||
if(source) {
|
if(source) {
|
||||||
for (var p in source) {
|
for(var p in source) {
|
||||||
if(object[p] === null || object[p] === undefined) {
|
if(object[p] === null || object[p] === undefined) {
|
||||||
object[p] = source[p];
|
object[p] = source[p];
|
||||||
}
|
}
|
||||||
@ -913,8 +913,8 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
|||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
CommonJS optional require.main property:
|
CommonJS optional require.main property:
|
||||||
In a browser we offer a fake main module which points back to the boot function
|
In a browser we offer a fake main module which points back to the boot function
|
||||||
(Theoretically, this may allow TW to eventually load itself as a module in the browser)
|
(Theoretically, this may allow TW to eventually load itself as a module in the browser)
|
||||||
*/
|
*/
|
||||||
Object.defineProperty(sandbox.require, "main", {
|
Object.defineProperty(sandbox.require, "main", {
|
||||||
value: (typeof(require) !== "undefined") ? require.main : {TiddlyWiki: _boot},
|
value: (typeof(require) !== "undefined") ? require.main : {TiddlyWiki: _boot},
|
||||||
@ -956,9 +956,9 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
|||||||
moduleInfo.exports = moduleInfo.definition;
|
moduleInfo.exports = moduleInfo.definition;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
if (e instanceof SyntaxError) {
|
if(e instanceof SyntaxError) {
|
||||||
var line = e.lineNumber || e.line; // Firefox || Safari
|
var line = e.lineNumber || e.line; // Firefox || Safari
|
||||||
if (typeof(line) != "undefined" && line !== null) {
|
if(typeof(line) != "undefined" && line !== null) {
|
||||||
$tw.utils.error("Syntax error in boot module " + name + ":" + line + ":\n" + e.stack);
|
$tw.utils.error("Syntax error in boot module " + name + ":" + line + ":\n" + e.stack);
|
||||||
} else if(!$tw.browser) {
|
} else if(!$tw.browser) {
|
||||||
// this is the only way to get node.js to display the line at which the syntax error appeared,
|
// this is the only way to get node.js to display the line at which the syntax error appeared,
|
||||||
@ -1553,7 +1553,7 @@ Define all modules stored in ordinary tiddlers
|
|||||||
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
||||||
this.each(function(tiddler,title) {
|
this.each(function(tiddler,title) {
|
||||||
if(tiddler.hasField("module-type")) {
|
if(tiddler.hasField("module-type")) {
|
||||||
switch (tiddler.fields.type) {
|
switch(tiddler.fields.type) {
|
||||||
case "application/javascript":
|
case "application/javascript":
|
||||||
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
||||||
if(!$tw.utils.hop($tw.modules.titles,tiddler.fields.title)) {
|
if(!$tw.utils.hop($tw.modules.titles,tiddler.fields.title)) {
|
||||||
@ -2090,7 +2090,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp,options) {
|
|||||||
arrayOfFiles = arrayOfFiles || [];
|
arrayOfFiles = arrayOfFiles || [];
|
||||||
var files = fs.readdirSync(dirPath);
|
var files = fs.readdirSync(dirPath);
|
||||||
files.forEach(function(file) {
|
files.forEach(function(file) {
|
||||||
if (recurse && fs.statSync(dirPath + path.sep + file).isDirectory()) {
|
if(recurse && fs.statSync(dirPath + path.sep + file).isDirectory()) {
|
||||||
arrayOfFiles = getAllFiles(dirPath + path.sep + file, recurse, arrayOfFiles);
|
arrayOfFiles = getAllFiles(dirPath + path.sep + file, recurse, arrayOfFiles);
|
||||||
} else if(fs.statSync(dirPath + path.sep + file).isFile()){
|
} else if(fs.statSync(dirPath + path.sep + file).isFile()){
|
||||||
arrayOfFiles.push(path.join(dirPath, path.sep, file));
|
arrayOfFiles.push(path.join(dirPath, path.sep, file));
|
||||||
@ -2259,13 +2259,16 @@ Returns an array of search paths
|
|||||||
*/
|
*/
|
||||||
$tw.getLibraryItemSearchPaths = function(libraryPath,envVar) {
|
$tw.getLibraryItemSearchPaths = function(libraryPath,envVar) {
|
||||||
var pluginPaths = [path.resolve($tw.boot.corePath,libraryPath)],
|
var pluginPaths = [path.resolve($tw.boot.corePath,libraryPath)],
|
||||||
|
env;
|
||||||
|
if(envVar) {
|
||||||
env = process.env[envVar];
|
env = process.env[envVar];
|
||||||
if(env) {
|
if(env) {
|
||||||
env.split(path.delimiter).map(function(item) {
|
env.split(path.delimiter).map(function(item) {
|
||||||
if(item) {
|
if(item) {
|
||||||
pluginPaths.push(item);
|
pluginPaths.push(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return pluginPaths;
|
return pluginPaths;
|
||||||
};
|
};
|
||||||
@ -2351,7 +2354,7 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
|
|||||||
}
|
}
|
||||||
$tw.wiki.addTiddlers(tiddlerFile.tiddlers);
|
$tw.wiki.addTiddlers(tiddlerFile.tiddlers);
|
||||||
});
|
});
|
||||||
if ($tw.boot.wikiPath == wikiPath) {
|
if($tw.boot.wikiPath == wikiPath) {
|
||||||
// Save the original tiddler file locations if requested
|
// Save the original tiddler file locations if requested
|
||||||
var output = {}, relativePath, fileInfo;
|
var output = {}, relativePath, fileInfo;
|
||||||
for(var title in $tw.boot.files) {
|
for(var title in $tw.boot.files) {
|
||||||
@ -2706,14 +2709,14 @@ $tw.boot.doesTaskMatchPlatform = function(taskModule) {
|
|||||||
var platforms = taskModule.platforms;
|
var platforms = taskModule.platforms;
|
||||||
if(platforms) {
|
if(platforms) {
|
||||||
for(var t=0; t<platforms.length; t++) {
|
for(var t=0; t<platforms.length; t++) {
|
||||||
switch (platforms[t]) {
|
switch(platforms[t]) {
|
||||||
case "browser":
|
case "browser":
|
||||||
if ($tw.browser) {
|
if($tw.browser) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "node":
|
case "node":
|
||||||
if ($tw.node) {
|
if($tw.node) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2796,7 +2799,7 @@ Invoke the hook by key
|
|||||||
$tw.hooks.invokeHook = function(hookName /*, value,... */) {
|
$tw.hooks.invokeHook = function(hookName /*, value,... */) {
|
||||||
var args = Array.prototype.slice.call(arguments,1);
|
var args = Array.prototype.slice.call(arguments,1);
|
||||||
if($tw.utils.hop($tw.hooks.names,hookName)) {
|
if($tw.utils.hop($tw.hooks.names,hookName)) {
|
||||||
for (var i = 0; i < $tw.hooks.names[hookName].length; i++) {
|
for(var i = 0; i < $tw.hooks.names[hookName].length; i++) {
|
||||||
args[0] = $tw.hooks.names[hookName][i].apply(null,args);
|
args[0] = $tw.hooks.names[hookName][i].apply(null,args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
title: $:/library/sjcl.js
|
|
||||||
type: application/javascript
|
|
||||||
library: yes
|
|
35
boot/tiddlywiki.files
Normal file
35
boot/tiddlywiki.files
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"tiddlers": [
|
||||||
|
{
|
||||||
|
"file": "sjcl.js",
|
||||||
|
"fields": {
|
||||||
|
"title": "$:/library/sjcl.js",
|
||||||
|
"type": "application/javascript",
|
||||||
|
"library": "yes"
|
||||||
|
},
|
||||||
|
"prefix": "(function(define) {\n",
|
||||||
|
"suffix": "\n})(function (_,defined){window.sjcl = defined()})\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "boot.js",
|
||||||
|
"fields": {
|
||||||
|
"title": "$:/boot/boot.js",
|
||||||
|
"type": "application/javascript"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "bootprefix.js",
|
||||||
|
"fields": {
|
||||||
|
"title": "$:/boot/bootprefix.js",
|
||||||
|
"type": "application/javascript"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "boot.css",
|
||||||
|
"fields": {
|
||||||
|
"title": "$:/boot/boot.css",
|
||||||
|
"type": "text/css"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
23
core/modules/utils/errors.js
Normal file
23
core/modules/utils/errors.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/utils/errors.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: utils
|
||||||
|
|
||||||
|
Custom errors for TiddlyWiki.
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
function TranscludeRecursionError() {
|
||||||
|
Error.apply(this,arguments);
|
||||||
|
this.signatures = Object.create(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Maximum permitted depth of the widget tree for recursion detection */
|
||||||
|
TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH = 1000;
|
||||||
|
|
||||||
|
TranscludeRecursionError.prototype = Object.create(Error);
|
||||||
|
|
||||||
|
exports.TranscludeRecursionError = TranscludeRecursionError;
|
||||||
|
|
||||||
|
})();
|
@ -14,8 +14,12 @@ Utilities for working with the TiddlyWiki repository file structure
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Get an object containing all the plugins as a hashmap by title of the JSON representation of the plugin
|
Get an object containing all the plugins as a hashmap by title of the JSON representation of the plugin
|
||||||
|
Options:
|
||||||
|
|
||||||
|
ignoreEnvironmentVariables: defaults to false
|
||||||
*/
|
*/
|
||||||
exports.getAllPlugins = function() {
|
exports.getAllPlugins = function(options) {
|
||||||
|
options = options || {};
|
||||||
var fs = require("fs"),
|
var fs = require("fs"),
|
||||||
path = require("path"),
|
path = require("path"),
|
||||||
tiddlers = {};
|
tiddlers = {};
|
||||||
@ -39,9 +43,9 @@ exports.getAllPlugins = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,$tw.config.pluginsEnvVar),collectPublisherPlugins);
|
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.pluginsEnvVar),collectPublisherPlugins);
|
||||||
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,$tw.config.themesEnvVar),collectPublisherPlugins);
|
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.themesEnvVar),collectPublisherPlugins);
|
||||||
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,$tw.config.languagesEnvVar),collectPlugins);
|
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.languagesEnvVar),collectPlugins);
|
||||||
return tiddlers;
|
return tiddlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -825,7 +825,7 @@ options.length .. number of characters returned defaults to 64
|
|||||||
*/
|
*/
|
||||||
exports.sha256 = function(str, options) {
|
exports.sha256 = function(str, options) {
|
||||||
options = options || {}
|
options = options || {}
|
||||||
return sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(str)).substr(0,options.length || 64);
|
return $tw.sjcl.codec.hex.fromBits($tw.sjcl.hash.sha256.hash(str)).substr(0,options.length || 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -77,8 +77,13 @@ TestCaseWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
this.setVariable("transclusion",$tw.utils.hashString(jsonPayload));
|
this.setVariable("transclusion",$tw.utils.hashString(jsonPayload));
|
||||||
// Generate a `payloadTiddlers` variable that contains the payload in JSON format
|
// Generate a `payloadTiddlers` variable that contains the payload in JSON format
|
||||||
this.setVariable("payloadTiddlers",jsonPayload);
|
this.setVariable("payloadTiddlers",jsonPayload);
|
||||||
|
// Only run the tests if the testcase output and expected results were specified, and those tiddlers actually exist in the wiki
|
||||||
|
var shouldRunTests = false;
|
||||||
|
if(this.testcaseTestOutput && this.testcaseWiki.tiddlerExists(this.testcaseTestOutput) && this.testcaseTestExpectedResult && this.testcaseWiki.tiddlerExists(this.testcaseTestExpectedResult)) {
|
||||||
|
shouldRunTests = true;
|
||||||
|
}
|
||||||
// Render the test rendering if required
|
// Render the test rendering if required
|
||||||
if(this.testcaseTestOutput && this.testcaseTestExpectedResult) {
|
if(shouldRunTests) {
|
||||||
var testcaseOutputContainer = $tw.fakeDocument.createElement("div");
|
var testcaseOutputContainer = $tw.fakeDocument.createElement("div");
|
||||||
var testcaseOutputWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTestOutput,{
|
var testcaseOutputWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTestOutput,{
|
||||||
document: $tw.fakeDocument,
|
document: $tw.fakeDocument,
|
||||||
@ -101,7 +106,7 @@ TestCaseWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
var testResult = "",
|
var testResult = "",
|
||||||
outputHTML = "",
|
outputHTML = "",
|
||||||
expectedHTML = "";
|
expectedHTML = "";
|
||||||
if(this.testcaseTestOutput && this.testcaseTestExpectedResult) {
|
if(shouldRunTests) {
|
||||||
outputHTML = testcaseOutputContainer.children[0].innerHTML;
|
outputHTML = testcaseOutputContainer.children[0].innerHTML;
|
||||||
expectedHTML = this.testcaseWiki.getTiddlerText(this.testcaseTestExpectedResult);
|
expectedHTML = this.testcaseWiki.getTiddlerText(this.testcaseTestExpectedResult);
|
||||||
if(outputHTML === expectedHTML) {
|
if(outputHTML === expectedHTML) {
|
||||||
|
@ -30,7 +30,30 @@ TranscludeWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
this.parentDomNode = parent;
|
this.parentDomNode = parent;
|
||||||
this.computeAttributes();
|
this.computeAttributes();
|
||||||
this.execute();
|
this.execute();
|
||||||
this.renderChildren(parent,nextSibling);
|
try {
|
||||||
|
this.renderChildren(parent,nextSibling);
|
||||||
|
} catch(error) {
|
||||||
|
if(error instanceof $tw.utils.TranscludeRecursionError) {
|
||||||
|
// We were infinite looping.
|
||||||
|
// We need to try and abort as much of the loop as we can, so we will keep "throwing" upward until we find a transclusion that has a different signature.
|
||||||
|
// Hopefully that will land us just outside where the loop began. That's where we want to issue an error.
|
||||||
|
// Rendering widgets beneath this point may result in a freezing browser if they explode exponentially.
|
||||||
|
var transcludeSignature = this.getVariable("transclusion");
|
||||||
|
if(this.getAncestorCount() > $tw.utils.TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH - 50) {
|
||||||
|
// For the first fifty transcludes we climb up, we simply collect signatures.
|
||||||
|
// We're assuming that those first 50 will likely include all transcludes involved in the loop.
|
||||||
|
error.signatures[transcludeSignature] = true;
|
||||||
|
} else if(!error.signatures[transcludeSignature]) {
|
||||||
|
// Now that we're past the first 50, let's look for the first signature that wasn't in the loop. That'll be where we print the error and resume rendering.
|
||||||
|
this.children = [this.makeChildWidget({type: "error", attributes: {
|
||||||
|
"$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")}
|
||||||
|
}})];
|
||||||
|
this.renderChildren(parent,nextSibling);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -12,9 +12,6 @@ Widget base class
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/* Maximum permitted depth of the widget tree for recursion detection */
|
|
||||||
var MAX_WIDGET_TREE_DEPTH = 1000;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create a widget object for a parse tree node
|
Create a widget object for a parse tree node
|
||||||
parseTreeNode: reference to the parse tree node to be rendered
|
parseTreeNode: reference to the parse tree node to be rendered
|
||||||
@ -494,10 +491,8 @@ Widget.prototype.makeChildWidgets = function(parseTreeNodes,options) {
|
|||||||
this.children = [];
|
this.children = [];
|
||||||
var self = this;
|
var self = this;
|
||||||
// Check for too much recursion
|
// Check for too much recursion
|
||||||
if(this.getAncestorCount() > MAX_WIDGET_TREE_DEPTH) {
|
if(this.getAncestorCount() > $tw.utils.TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH) {
|
||||||
this.children.push(this.makeChildWidget({type: "error", attributes: {
|
throw new $tw.utils.TranscludeRecursionError();
|
||||||
"$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")}
|
|
||||||
}}));
|
|
||||||
} else {
|
} else {
|
||||||
// Create set variable widgets for each variable
|
// Create set variable widgets for each variable
|
||||||
$tw.utils.each(options.variables,function(value,name) {
|
$tw.utils.each(options.variables,function(value,name) {
|
||||||
|
@ -5,6 +5,7 @@ title: $:/core/ui/TestCaseTemplate
|
|||||||
<$let
|
<$let
|
||||||
linkTarget="yes"
|
linkTarget="yes"
|
||||||
displayFormat={{!!display-format}}
|
displayFormat={{!!display-format}}
|
||||||
|
testcaseTiddler=<<currentTiddler>>
|
||||||
>
|
>
|
||||||
<$testcase
|
<$testcase
|
||||||
testOutput="Output"
|
testOutput="Output"
|
||||||
|
@ -15,7 +15,7 @@ title: $:/core/ui/testcases/DefaultTemplate
|
|||||||
<div class="tc-test-case-wrapper">
|
<div class="tc-test-case-wrapper">
|
||||||
<div class="tc-test-case-header">
|
<div class="tc-test-case-header">
|
||||||
<h2>
|
<h2>
|
||||||
<$genesis $type={{{ [<linkTarget>!match[]then[$link]else[div]] }}}>
|
<$genesis $type={{{ [<linkTarget>!match[]then[$link]else[div]] }}} to=<<testcaseTiddler>>>
|
||||||
<%if [<testResult>!match[]] %>
|
<%if [<testResult>!match[]] %>
|
||||||
<span class={{{ tc-test-case-result-icon [<testResult>!match[fail]then[tc-test-case-result-icon-pass]] [<testResult>match[fail]then[tc-test-case-result-icon-fail]] +[join[ ]] }}}>
|
<span class={{{ tc-test-case-result-icon [<testResult>!match[fail]then[tc-test-case-result-icon-pass]] [<testResult>match[fail]then[tc-test-case-result-icon-fail]] +[join[ ]] }}}>
|
||||||
<%if [<testResult>!match[fail]] %>
|
<%if [<testResult>!match[fail]] %>
|
||||||
@ -55,7 +55,9 @@ title: $:/core/ui/testcases/DefaultTemplate
|
|||||||
<pre><$view tiddler="Output" format="plainwikified" mode="block"/></pre>
|
<pre><$view tiddler="Output" format="plainwikified" mode="block"/></pre>
|
||||||
<%else%>
|
<%else%>
|
||||||
<$linkcatcher actions=<<linkcatcherActions>>>
|
<$linkcatcher actions=<<linkcatcherActions>>>
|
||||||
<$transclude $tiddler="Output" $mode="block"/>
|
<$tiddler tiddler="Output">
|
||||||
|
<$transclude $tiddler="Output" $mode="block"/>
|
||||||
|
</$tiddler>
|
||||||
</$linkcatcher>
|
</$linkcatcher>
|
||||||
<%endif%>
|
<%endif%>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,8 @@ title: Output
|
|||||||
|
|
||||||
\whitespace trim
|
\whitespace trim
|
||||||
<$transclude $tiddler="Output"/>
|
<$transclude $tiddler="Output"/>
|
||||||
|
|
||||||
+
|
+
|
||||||
title: ExpectedResult
|
title: ExpectedResult
|
||||||
|
|
||||||
<p><span class="tc-error">Recursive transclusion error in transclude widget</span></p>
|
<span class="tc-error">Recursive transclusion error in transclude widget</span>
|
@ -17,7 +17,7 @@ if($tw.node) {
|
|||||||
describe("Plugin tests", function() {
|
describe("Plugin tests", function() {
|
||||||
|
|
||||||
// Get all the plugins as a hashmap by title of a JSON string with the plugin content
|
// Get all the plugins as a hashmap by title of a JSON string with the plugin content
|
||||||
var tiddlers = $tw.utils.getAllPlugins();
|
var tiddlers = $tw.utils.getAllPlugins({ignoreEnvironmentVariables: true});
|
||||||
// console.log(JSON.stringify(Object.keys(tiddlers),null,4));
|
// console.log(JSON.stringify(Object.keys(tiddlers),null,4));
|
||||||
describe("every plugin should have the required standard fields", function() {
|
describe("every plugin should have the required standard fields", function() {
|
||||||
var titles = Object.keys(tiddlers);
|
var titles = Object.keys(tiddlers);
|
||||||
|
@ -160,6 +160,47 @@ describe("Widget module", function() {
|
|||||||
expect(wrapper.innerHTML).toBe("<span class=\"tc-error\">Recursive transclusion error in transclude widget</span>");
|
expect(wrapper.innerHTML).toBe("<span class=\"tc-error\">Recursive transclusion error in transclude widget</span>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should handle single-tiddler recursion with branching nodes", function() {
|
||||||
|
var wiki = new $tw.Wiki();
|
||||||
|
// Add a tiddler
|
||||||
|
wiki.addTiddlers([
|
||||||
|
{title: "TiddlerOne", text: "<$tiddler tiddler='TiddlerOne'><$transclude /> <$transclude /></$tiddler>"},
|
||||||
|
]);
|
||||||
|
// Test parse tree
|
||||||
|
var parseTreeNode = {type: "widget", children: [
|
||||||
|
{type: "transclude", attributes: {
|
||||||
|
"tiddler": {type: "string", value: "TiddlerOne"}
|
||||||
|
}}
|
||||||
|
]};
|
||||||
|
// Construct the widget node
|
||||||
|
var widgetNode = createWidgetNode(parseTreeNode,wiki);
|
||||||
|
// Render the widget node to the DOM
|
||||||
|
var wrapper = renderWidgetNode(widgetNode);
|
||||||
|
// Test the rendering
|
||||||
|
expect(wrapper.innerHTML).toBe("<span class=\"tc-error\">Recursive transclusion error in transclude widget</span> <span class=\"tc-error\">Recursive transclusion error in transclude widget</span>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle many-tiddler recursion with branching nodes", function() {
|
||||||
|
var wiki = new $tw.Wiki();
|
||||||
|
// Add a tiddler
|
||||||
|
wiki.addTiddlers([
|
||||||
|
{title: "TiddlerOne", text: "<$transclude tiddler='TiddlerTwo'/> <$transclude tiddler='TiddlerTwo'/>"},
|
||||||
|
{title: "TiddlerTwo", text: "<$transclude tiddler='TiddlerOne'/>"}
|
||||||
|
]);
|
||||||
|
// Test parse tree
|
||||||
|
var parseTreeNode = {type: "widget", children: [
|
||||||
|
{type: "transclude", attributes: {
|
||||||
|
"tiddler": {type: "string", value: "TiddlerOne"}
|
||||||
|
}}
|
||||||
|
]};
|
||||||
|
// Construct the widget node
|
||||||
|
var widgetNode = createWidgetNode(parseTreeNode,wiki);
|
||||||
|
// Render the widget node to the DOM
|
||||||
|
var wrapper = renderWidgetNode(widgetNode);
|
||||||
|
// Test the rendering
|
||||||
|
expect(wrapper.innerHTML).toBe("<span class=\"tc-error\">Recursive transclusion error in transclude widget</span>");
|
||||||
|
});
|
||||||
|
|
||||||
it("should deal with SVG elements", function() {
|
it("should deal with SVG elements", function() {
|
||||||
var wiki = new $tw.Wiki();
|
var wiki = new $tw.Wiki();
|
||||||
// Construct the widget node
|
// Construct the widget node
|
||||||
|
@ -23,5 +23,4 @@ Some payload tiddlers are set aside for special purposes:
|
|||||||
|''Narrative'' |Narrative description of the test, intended to explain the purpose and operation of the test |
|
|''Narrative'' |Narrative description of the test, intended to explain the purpose and operation of the test |
|
||||||
|''Output'' |The tiddler that produces the test output |
|
|''Output'' |The tiddler that produces the test output |
|
||||||
|''~ExpectedResult'' |HTML of expected result of rendering the ''Output'' tiddler |
|
|''~ExpectedResult'' |HTML of expected result of rendering the ''Output'' tiddler |
|
||||||
|
|''Description'' |Set to the text of the <<.field description>> field |
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ description: An example of a failing test
|
|||||||
|
|
||||||
title: Narrative
|
title: Narrative
|
||||||
|
|
||||||
This test case intentionally fails to show how failures are displayed.
|
This test case intentionally fails (in order to show how failures are displayed)
|
||||||
+
|
+
|
||||||
title: Output
|
title: Output
|
||||||
|
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
title: TestCases/TestCaseWidget/NoExpectedResults
|
||||||
|
type: text/vnd.tiddlywiki-multiple
|
||||||
|
tags: [[$:/tags/wiki-test-spec]]
|
||||||
|
description: A testcase that does not specify expected results
|
||||||
|
|
||||||
|
title: Narrative
|
||||||
|
|
||||||
|
This testcase will display without the pass/fail icons because it does not include an `ExpectedResults` tiddler, and so will only be rendered, and not be executed as a test
|
||||||
|
+
|
||||||
|
title: Output
|
||||||
|
|
||||||
|
This is the output
|
@ -75,7 +75,7 @@ The test case wiki will inherit variables that are visible to the <<.wid testcas
|
|||||||
|
|
||||||
A custom template can be specified for special purposes. For example, the provided template $:/core/ui/testcases/RawJSONTemplate just displays the payload tiddlers in JSON, which can be used for debugging purposes.
|
A custom template can be specified for special purposes. For example, the provided template $:/core/ui/testcases/RawJSONTemplate just displays the payload tiddlers in JSON, which can be used for debugging purposes.
|
||||||
|
|
||||||
! Test Czase Template Variables
|
! Test Case Template Variables
|
||||||
|
|
||||||
The <<.wid testcase>> widget makes the following variables available within the rendered template:
|
The <<.wid testcase>> widget makes the following variables available within the rendered template:
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ name: 具可读性的插件条目的名称
|
|||||||
parent-plugin: 对于一个插件,指定其为哪个插件的子插件
|
parent-plugin: 对于一个插件,指定其为哪个插件的子插件
|
||||||
plugin-priority: 插件条目的优先级数值
|
plugin-priority: 插件条目的优先级数值
|
||||||
plugin-type: 插件条目的类型
|
plugin-type: 插件条目的类型
|
||||||
|
stability: 插件的开发状态:已弃用、实验性、稳定或旧版
|
||||||
released: TiddlyWiki 的发布日期
|
released: TiddlyWiki 的发布日期
|
||||||
revision: 条目存放于服务器中的修订版本
|
revision: 条目存放于服务器中的修订版本
|
||||||
source: 条目的网址
|
source: 条目的网址
|
||||||
|
@ -30,6 +30,7 @@ name: 具可讀性的套件條目的名稱
|
|||||||
parent-plugin: 對於一個插件,指定其為哪個插件的子插件
|
parent-plugin: 對於一個插件,指定其為哪個插件的子插件
|
||||||
plugin-priority: 套件條目的優先級數值
|
plugin-priority: 套件條目的優先級數值
|
||||||
plugin-type: 套件條目的類型
|
plugin-type: 套件條目的類型
|
||||||
|
stability: 插件的開發狀態:已棄用、實驗性、穩定或舊版
|
||||||
released: TiddlyWiki 的釋出日期
|
released: TiddlyWiki 的釋出日期
|
||||||
revision: 條目存放於伺服器中的修訂版本
|
revision: 條目存放於伺服器中的修訂版本
|
||||||
source: 條目的網址
|
source: 條目的網址
|
||||||
|
@ -34,23 +34,22 @@ describe("Wiki-based tests", function() {
|
|||||||
if(!wiki.tiddlerExists("Output")) {
|
if(!wiki.tiddlerExists("Output")) {
|
||||||
throw "Missing 'Output' tiddler";
|
throw "Missing 'Output' tiddler";
|
||||||
}
|
}
|
||||||
if(!wiki.tiddlerExists("ExpectedResult")) {
|
if(wiki.tiddlerExists("ExpectedResult")) {
|
||||||
throw "Missing 'ExpectedResult' tiddler";
|
// Construct the widget node
|
||||||
|
var text = "{{Output}}\n\n";
|
||||||
|
var widgetNode = createWidgetNode(parseText(text,wiki),wiki);
|
||||||
|
// Render the widget node to the DOM
|
||||||
|
var wrapper = renderWidgetNode(widgetNode);
|
||||||
|
// Clear changes queue
|
||||||
|
wiki.clearTiddlerEventQueue();
|
||||||
|
// Run the actions if provided
|
||||||
|
if(wiki.tiddlerExists("Actions")) {
|
||||||
|
widgetNode.invokeActionString(wiki.getTiddlerText("Actions"));
|
||||||
|
refreshWidgetNode(widgetNode,wrapper);
|
||||||
|
}
|
||||||
|
// Test the rendering
|
||||||
|
expect(wrapper.innerHTML).toBe(wiki.getTiddlerText("ExpectedResult"));
|
||||||
}
|
}
|
||||||
// Construct the widget node
|
|
||||||
var text = "{{Output}}\n\n";
|
|
||||||
var widgetNode = createWidgetNode(parseText(text,wiki),wiki);
|
|
||||||
// Render the widget node to the DOM
|
|
||||||
var wrapper = renderWidgetNode(widgetNode);
|
|
||||||
// Clear changes queue
|
|
||||||
wiki.clearTiddlerEventQueue();
|
|
||||||
// Run the actions if provided
|
|
||||||
if(wiki.tiddlerExists("Actions")) {
|
|
||||||
widgetNode.invokeActionString(wiki.getTiddlerText("Actions"));
|
|
||||||
refreshWidgetNode(widgetNode,wrapper);
|
|
||||||
}
|
|
||||||
// Test the rendering
|
|
||||||
expect(wrapper.innerHTML).toBe(wiki.getTiddlerText("ExpectedResult"));
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user