diff --git a/boot/boot.css.tid b/boot/boot.css similarity index 96% rename from boot/boot.css.tid rename to boot/boot.css index 27c8884cd..c0d15f1e3 100644 --- a/boot/boot.css.tid +++ b/boot/boot.css @@ -1,6 +1,3 @@ -title: $:/boot/boot.css -type: text/css - /* Basic styles used before we boot up the parsing engine */ diff --git a/boot/boot.js b/boot/boot.js index d993499b6..ea20c83fd 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -142,15 +142,15 @@ $tw.utils.each = function(object,callback) { var next,f,length; if(object) { if(Object.prototype.toString.call(object) == "[object Array]") { - for (f=0, length=object.length; f $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; + } }; /* diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index 69f63a684..056529c20 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -12,9 +12,6 @@ Widget base class /*global $tw: false */ "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 parseTreeNode: reference to the parse tree node to be rendered @@ -166,6 +163,8 @@ Widget.prototype.getVariableInfo = function(name,options) { }); resultList = this.wiki.filterTiddlers(value,this.makeFakeWidgetWithVariables(variables),options.source); value = resultList[0] || ""; + } else { + params = variable.params; } return { text: value, @@ -494,10 +493,8 @@ Widget.prototype.makeChildWidgets = function(parseTreeNodes,options) { this.children = []; var self = this; // Check for too much recursion - if(this.getAncestorCount() > MAX_WIDGET_TREE_DEPTH) { - this.children.push(this.makeChildWidget({type: "error", attributes: { - "$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")} - }})); + if(this.getAncestorCount() > $tw.utils.TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH) { + throw new $tw.utils.TranscludeRecursionError(); } else { // Create set variable widgets for each variable $tw.utils.each(options.variables,function(value,name) { diff --git a/core/ui/TestCaseTemplate.tid b/core/ui/TestCaseTemplate.tid index 74b6ab27d..9871a2904 100644 --- a/core/ui/TestCaseTemplate.tid +++ b/core/ui/TestCaseTemplate.tid @@ -5,6 +5,7 @@ title: $:/core/ui/TestCaseTemplate <$let linkTarget="yes" displayFormat={{!!display-format}} + testcaseTiddler=<> > <$testcase testOutput="Output" diff --git a/core/ui/TestCases/DefaultTemplate.tid b/core/ui/TestCases/DefaultTemplate.tid index 679620969..3a68253e8 100644 --- a/core/ui/TestCases/DefaultTemplate.tid +++ b/core/ui/TestCases/DefaultTemplate.tid @@ -15,7 +15,7 @@ title: $:/core/ui/testcases/DefaultTemplate

- <$genesis $type={{{ [!match[]then[$link]else[div]] }}}> + <$genesis $type={{{ [!match[]then[$link]else[div]] }}} to=<>> <%if [!match[]] %> !match[fail]then[tc-test-case-result-icon-pass]] [match[fail]then[tc-test-case-result-icon-fail]] +[join[ ]] }}}> <%if [!match[fail]] %> @@ -55,7 +55,9 @@ title: $:/core/ui/testcases/DefaultTemplate
<$view tiddler="Output" format="plainwikified" mode="block"/>
<%else%> <$linkcatcher actions=<>> - <$transclude $tiddler="Output" $mode="block"/> + <$tiddler tiddler="Output"> + <$transclude $tiddler="Output" $mode="block"/> + <%endif%>

diff --git a/core/wiki/config/OfficialPluginLibrary.tid b/core/wiki/config/OfficialPluginLibrary.tid index 3b2f3b829..ed4a78d6a 100644 --- a/core/wiki/config/OfficialPluginLibrary.tid +++ b/core/wiki/config/OfficialPluginLibrary.tid @@ -1,6 +1,6 @@ -caption: {{$:/language/OfficialPluginLibrary}} -tags: $:/tags/PluginLibrary title: $:/config/OfficialPluginLibrary -url: https://tiddlywiki5-git-plugin-stability-badges-jermolenes-projects.vercel.app/library/v5.3.3/index.html +tags: $:/tags/PluginLibrary +url: https://tiddlywiki.com/library/v5.3.4/index.html +caption: {{$:/language/OfficialPluginLibrary}} -Plugin library for https://tiddlywiki5-git-plugin-stability-badges-jermolenes-projects.vercel.app \ No newline at end of file +{{$:/language/OfficialPluginLibrary/Hint}} diff --git a/editions/prerelease/tiddlers/Release 5.3.4.tid b/editions/prerelease/tiddlers/Release 5.3.4.tid index 638afaaa2..b88a8feb8 100644 --- a/editions/prerelease/tiddlers/Release 5.3.4.tid +++ b/editions/prerelease/tiddlers/Release 5.3.4.tid @@ -1,6 +1,6 @@ caption: 5.3.4 -created: 20231223102229103 -modified: 20231223102229103 +created: 20240529100240232 +modified: 20240529100240232 tags: ReleaseNotes title: Release 5.3.4 type: text/vnd.tiddlywiki @@ -10,6 +10,8 @@ description: Under development ! Major Improvements +!! Tour Plugin + <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7734">> several new features that together allow interactive learning tours to be created and presented in TiddlyWiki. The demo TiddlyWiki interactive tour can be seen at https://tiddlywiki.com/prerelease/tour @@ -20,6 +22,20 @@ The new features include: * The new Confetti Plugin that allows animated bursts of confetti to be displayed * Improvements to the Dynannotate Plugin to add the ability to highlight screen elements using an animated spotlight effect +!! <<.wlink TestCaseWidget>> Widget + +<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7817">> new <<.wlink TestCaseWidget>> widget that is intended to solve a problem with the examples that we feature in the documentation. The existing macros are workable for simple, self-contained examples, but can be hard to follow in cases where the examples use additional tiddlers. The <<.wlink TestCaseWidget>> widget displays complete, self-contained interactive examples showing the output together with a tabbed display of the constituent tiddlers that produce it: + +<> + +The payload tiddlers for a test case are specified with the <<.wlink DataWidget>> widget. Test cases are run as an independent, self-contained nested wiki in a similar way to the [[Innerwiki Plugin]], but are much more lightweight. The disadvantage is that test cases are rendered as part of the main page, and so any styling changes will leak out to the rest of the page. + +Test cases can also specify the raw HTML of the expected result which causes them to be executed as tests, with success or failure indicated by an icon: + +<> + +The easiest way to use the <<.wlink TestCaseWidget>> is by creating TestCaseTiddlers using the new CompoundTiddlers format. There are also many test cases to view in the TiddlyWiki test edition at https://tiddlywiki.com/prerelease/test.html + ! Translation improvements Improvements to the following translations: @@ -30,7 +46,7 @@ Improvements to the following translations: ! Plugin Improvements -* +* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/8198">> badges to the core plugins to indicate their [[stability level|Plugin Stability]] from "deprecated", "experimental", "stable" and "legacy". These badges are shown in the plugin library and in the control panel ! Widget Improvements @@ -46,11 +62,13 @@ Improvements to the following translations: ! Hackability Improvements +* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7882">> infinite recursion handling using a custom exception * <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7966">> button to the JavaScript error popup allowing tiddlers to be saved to a local JSON file * <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/issues/8120">> to latest version of modern-normalize 2.0.0 ! Bug Fixes +* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/8186">> nested [[Block Quotes in WikiText]] * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7933">> TiddlyWikiClassic build process * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7935">> LinkWidget not refreshing when the `to` attribute changes * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/3460">> parsing bug with empty procedures/macros @@ -79,7 +97,8 @@ Improvements to the following translations: ! Developer Improvements -* +* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/8195">> issue with fakedom TW_Node inheritence +* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/8099">> SJCL library creating variables in global scope ! Infrastructure Improvements @@ -114,5 +133,6 @@ rmunn saqimtiaz sarna Telumire +twMat yaisog """>> diff --git a/editions/prerelease/tiddlers/system/PrereleaseOfficialPluginLibrary.tid b/editions/prerelease/tiddlers/system/PrereleaseOfficialPluginLibrary.tid index 3b2f3b829..07b5ab48a 100644 --- a/editions/prerelease/tiddlers/system/PrereleaseOfficialPluginLibrary.tid +++ b/editions/prerelease/tiddlers/system/PrereleaseOfficialPluginLibrary.tid @@ -1,6 +1,6 @@ -caption: {{$:/language/OfficialPluginLibrary}} -tags: $:/tags/PluginLibrary title: $:/config/OfficialPluginLibrary -url: https://tiddlywiki5-git-plugin-stability-badges-jermolenes-projects.vercel.app/library/v5.3.3/index.html +tags: $:/tags/PluginLibrary +url: https://tiddlywiki.com/prerelease/library/v5.3.4/index.html +caption: {{$:/language/OfficialPluginLibrary}} (Prerelease) -Plugin library for https://tiddlywiki5-git-plugin-stability-badges-jermolenes-projects.vercel.app \ No newline at end of file +The prerelease version of the official ~TiddlyWiki plugin library at tiddlywiki.com. Plugins, themes and language packs are maintained by the core team. diff --git a/editions/test/tiddlers/tests/data/transclude/Recursion.tid b/editions/test/tiddlers/tests/data/transclude/Recursion.tid index d75e671eb..b834f3765 100644 --- a/editions/test/tiddlers/tests/data/transclude/Recursion.tid +++ b/editions/test/tiddlers/tests/data/transclude/Recursion.tid @@ -7,7 +7,8 @@ title: Output \whitespace trim <$transclude $tiddler="Output"/> + + title: ExpectedResult -

Recursive transclusion error in transclude widget

\ No newline at end of file +Recursive transclusion error in transclude widget \ No newline at end of file diff --git a/editions/test/tiddlers/tests/test-backlinks.js b/editions/test/tiddlers/tests/test-backlinks.js index 68ad18bbd..ea7c2b7b4 100644 --- a/editions/test/tiddlers/tests/test-backlinks.js +++ b/editions/test/tiddlers/tests/test-backlinks.js @@ -12,6 +12,24 @@ Tests the backlinks mechanism. "use strict"; describe('Backlinks tests', function() { + function setupWiki(wikiOptions) { + wikiOptions = wikiOptions || {}; + // Create a wiki + var wiki = new $tw.Wiki(wikiOptions); + wiki.addIndexersToWiki(); + + wiki.addTiddler({ + title: 'TestIncoming', + text: '', + }); + + wiki.addTiddler({ + title: 'TestOutgoing', + text: 'A link to [[TestIncoming]]', + }); + return wiki; + } + describe('a tiddler with no links to it', function() { var wiki = new $tw.Wiki(); @@ -25,15 +43,7 @@ describe('Backlinks tests', function() { }); describe('A tiddler added to the wiki with a link to it', function() { - var wiki = new $tw.Wiki(); - - wiki.addTiddler({ - title: 'TestIncoming', - text: ''}); - - wiki.addTiddler({ - title: 'TestOutgoing', - text: 'A link to [[TestIncoming]]'}); + var wiki = setupWiki(); it('should have a backlink', function() { expect(wiki.filterTiddlers('TestIncoming +[backlinks[]]').join(',')).toBe('TestOutgoing'); @@ -42,15 +52,7 @@ describe('Backlinks tests', function() { describe('A tiddler that has a link added to it later', function() { it('should have an additional backlink', function() { - var wiki = new $tw.Wiki(); - - wiki.addTiddler({ - title: 'TestIncoming', - text: ''}); - - wiki.addTiddler({ - title: 'TestOutgoing', - text: 'A link to [[TestIncoming]]'}); + var wiki = setupWiki(); wiki.addTiddler({ title: 'TestOutgoing2', @@ -67,15 +69,7 @@ describe('Backlinks tests', function() { }); describe('A tiddler that has a link remove from it later', function() { - var wiki = new $tw.Wiki(); - - wiki.addTiddler({ - title: 'TestIncoming', - text: ''}); - - wiki.addTiddler({ - title: 'TestOutgoing', - text: 'A link to [[TestIncoming]]'}); + var wiki = setupWiki(); it('should have one fewer backlink', function() { expect(wiki.filterTiddlers('TestIncoming +[backlinks[]]').join(',')).toBe('TestOutgoing'); @@ -89,15 +83,7 @@ describe('Backlinks tests', function() { }); describe('A tiddler linking to another that gets renamed', function() { - var wiki = new $tw.Wiki(); - - wiki.addTiddler({ - title: 'TestIncoming', - text: ''}); - - wiki.addTiddler({ - title: 'TestOutgoing', - text: 'A link to [[TestIncoming]]'}); + var wiki = setupWiki(); it('should have its name changed in the backlinks', function() { expect(wiki.filterTiddlers('TestIncoming +[backlinks[]]').join(',')).toBe('TestOutgoing'); @@ -109,15 +95,7 @@ describe('Backlinks tests', function() { }); describe('A tiddler linking to another that gets deleted', function() { - var wiki = new $tw.Wiki(); - - wiki.addTiddler({ - title: 'TestIncoming', - text: ''}); - - wiki.addTiddler({ - title: 'TestOutgoing', - text: 'A link to [[TestIncoming]]'}); + var wiki = setupWiki(); it('should be removed from backlinks', function() { expect(wiki.filterTiddlers('TestIncoming +[backlinks[]]').join(',')).toBe('TestOutgoing'); @@ -127,6 +105,41 @@ describe('Backlinks tests', function() { expect(wiki.filterTiddlers('TestIncoming +[backlinks[]]').join(',')).toBe(''); }); }); + + describe('Binary tiddlers should not be parsed', function() { + var wiki = setupWiki(); + + wiki.addTiddler({ + title: 'TestDoc.doc', + text: 'A link to [[TestOutgoing]]', + type: 'application/msword' + }); + + wiki.addTiddler({ + title: 'TestExcel.xls', + text: 'A link to [[TestOutgoing]]', + type: 'application/excel' + }); + + wiki.addTiddler({ + title: 'TestOutgoing', + text: 'Some links to [[TestDoc.doc]] and [[TestExcel.xls]].' + }); + + it('should ignore office files', function() { + expect(wiki.getIndexer("BackIndexer").subIndexers.link._getTarget(wiki.getTiddler('TestExcel.xls'))).toEqual([]); + + expect(wiki.filterTiddlers('[all[]] +[backlinks[]]').join(',')).toBe('TestOutgoing'); + + // make it tw5 tiddler + wiki.addTiddler({ + title: 'TestExcel.xls', + text: 'A link to [[TestOutgoing]]' + }); + + expect(wiki.filterTiddlers('[all[]] +[backlinks[]]').join(',')).toBe('TestOutgoing,TestExcel.xls'); + }); + }); }); })(); diff --git a/editions/test/tiddlers/tests/test-fakedom.js b/editions/test/tiddlers/tests/test-fakedom.js new file mode 100644 index 000000000..7041f017b --- /dev/null +++ b/editions/test/tiddlers/tests/test-fakedom.js @@ -0,0 +1,27 @@ +/*\ +title: test-fakedom.js +type: application/javascript +tags: [[$:/tags/test-spec]] + +Tests the fakedom that Tiddlywiki occasionally uses. + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +describe("fakedom tests", function() { + + it("properly assigns nodeType based on DOM standards", function() { + // According to MDN, ELEMENT_NODE == 1 && TEXT_NODE == 3 + // There are others, but currently they're not implemented in fakedom + expect($tw.fakeDocument.createElement("div").nodeType).toBe(1); + expect($tw.fakeDocument.createElement("div").ELEMENT_NODE).toBe(1); + expect($tw.fakeDocument.createTextNode("text").nodeType).toBe(3); + expect($tw.fakeDocument.createTextNode("text").TEXT_NODE).toBe(3); + }); +}); + +})(); diff --git a/editions/test/tiddlers/tests/test-plugins.js b/editions/test/tiddlers/tests/test-plugins.js index 29ba4a829..663192a9c 100644 --- a/editions/test/tiddlers/tests/test-plugins.js +++ b/editions/test/tiddlers/tests/test-plugins.js @@ -17,7 +17,7 @@ if($tw.node) { describe("Plugin tests", function() { // 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)); describe("every plugin should have the required standard fields", function() { var titles = Object.keys(tiddlers); diff --git a/editions/test/tiddlers/tests/test-widget-getVariableInfo.js b/editions/test/tiddlers/tests/test-widget-getVariableInfo.js new file mode 100644 index 000000000..7273a6dce --- /dev/null +++ b/editions/test/tiddlers/tests/test-widget-getVariableInfo.js @@ -0,0 +1,95 @@ +/*\ +title: test-widget-getVariableInfo.js +type: application/javascript +tags: [[$:/tags/test-spec]] + +Tests the wikitext rendering pipeline end-to-end. We also need tests that individually test parsers, rendertreenodes etc., but this gets us started. + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +describe("Widget module", function() { + + var widget = require("$:/core/modules/widgets/widget.js"); + + function createWidgetNode(parseTreeNode,wiki) { + return new widget.widget(parseTreeNode,{ + wiki: wiki, + document: $tw.fakeDocument + }); + } + + function parseText(text,wiki,options) { + var parser = wiki.parseText("text/vnd.tiddlywiki",text,options); + return parser ? {type: "widget", children: parser.tree} : undefined; + } + + function renderWidgetNode(widgetNode) { + $tw.fakeDocument.setSequenceNumber(0); + var wrapper = $tw.fakeDocument.createElement("div"); + widgetNode.render(wrapper,null); +// console.log(require("util").inspect(wrapper,{depth: 8})); + return wrapper; + } + + function refreshWidgetNode(widgetNode,wrapper,changes) { + var changedTiddlers = {}; + if(changes) { + $tw.utils.each(changes,function(title) { + changedTiddlers[title] = true; + }); + } + widgetNode.refresh(changedTiddlers,wrapper,null); +// console.log(require("util").inspect(wrapper,{depth: 8})); + } + + it("should make sure that getVariableInfo returns all expected parameters", function() { + var wiki = new $tw.Wiki(); + wiki.addTiddlers([ + {title: "A", text: "\\define macro(a:aa) aaa"}, + {title: "B", text: "\\function fn(f:ff) fff\n\\function x() []"}, + {title: "C", text: "\\procedure proc(p:pp) ppp"}, + {title: "D", text: "\\widget $my.widget(w:ww) www"} + ]); + var text = "\\import A B C D\n\n<$let abc=def>"; + var widgetNode = createWidgetNode(parseText(text,wiki),wiki); + // Render the widget node to the DOM + renderWidgetNode(widgetNode); + var childNode = widgetNode; + while(childNode.children.length > 0) { + childNode = childNode.children[0]; + } + + expect(childNode.getVariableInfo("macro",{allowSelfAssigned:true}).params).toEqual([{name:"a",value:"aa"}]); + + // function params + expect(childNode.getVariableInfo("fn", {allowSelfAssigned:true}).params).toEqual([{name:"f",value:"ff"}]); + // functions have a text and a value + expect(childNode.getVariableInfo("x", {allowSelfAssigned:true}).text).toBe("fff"); + expect(childNode.getVariableInfo("x", {allowSelfAssigned:true}).srcVariable.value).toBe("[]"); + + // procedures and widgets failed prior to v5.3.4 + expect(childNode.getVariableInfo("proc", {allowSelfAssigned:true}).params).toEqual([{name:"p",default:"pp"}]); + expect(childNode.getVariableInfo("$my.widget", {allowSelfAssigned:true}).params).toEqual([{name:"w",default:"ww"}]); + + // no params expected + expect(childNode.getVariableInfo("abc", {allowSelfAssigned:true})).toEqual({text:"def"}); + + // debugger; Find code in browser + + // Find values to be compated to + // console.log("macro", childNode.getVariableInfo("macro",{allowSelfAssigned:true})); + // console.log("function", childNode.getVariableInfo("fn",{allowSelfAssigned:true})); + // console.log("function x", childNode.getVariableInfo("x",{allowSelfAssigned:true})); + // console.log("procedure", childNode.getVariableInfo("proc",{allowSelfAssigned:true})); + // console.log("widget", childNode.getVariableInfo("$my.widget",{allowSelfAssigned:true})); + // console.log("let", childNode.getVariableInfo("abc",{allowSelfAssigned:true})); + }); + +}); + +})(); diff --git a/editions/test/tiddlers/tests/test-widget.js b/editions/test/tiddlers/tests/test-widget.js index 0d1351f31..1c7665a53 100755 --- a/editions/test/tiddlers/tests/test-widget.js +++ b/editions/test/tiddlers/tests/test-widget.js @@ -160,6 +160,47 @@ describe("Widget module", function() { expect(wrapper.innerHTML).toBe("Recursive transclusion error in transclude widget"); }); + 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 />"}, + ]); + // 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("Recursive transclusion error in transclude widget Recursive transclusion error in transclude widget"); + }); + + 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("Recursive transclusion error in transclude widget"); + }); + it("should deal with SVG elements", function() { var wiki = new $tw.Wiki(); // Construct the widget node diff --git a/editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid b/editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid index ff84d6800..cf42c67d7 100644 --- a/editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid +++ b/editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid @@ -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 | |''Output'' |The tiddler that produces the test output | |''~ExpectedResult'' |HTML of expected result of rendering the ''Output'' tiddler | - - +|''Description'' |Set to the text of the <<.field description>> field | diff --git a/editions/tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid index bd9126e03..5524a9852 100644 --- a/editions/tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid +++ b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid @@ -5,7 +5,7 @@ description: An example of a failing test 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 diff --git a/editions/tw5.com/tiddlers/testcases/TestCaseWidget/NoExpectedResults.tid b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/NoExpectedResults.tid new file mode 100644 index 000000000..a4dcee462 --- /dev/null +++ b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/NoExpectedResults.tid @@ -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 diff --git a/editions/tw5.com/tiddlers/testcases/TestCaseWidget/TwoPlusTwo.tid b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/TwoPlusTwo.tid new file mode 100644 index 000000000..d08260e68 --- /dev/null +++ b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/TwoPlusTwo.tid @@ -0,0 +1,18 @@ +title: TestCases/TestCaseWidget/TwoPlusTwo +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec-failing]] +description: A testcase to calculate 2+2 + +title: Narrative + +This test case shows an elaborate way to calculate 2+2 involving multiple tiddlers ++ +title: Output + +The sum is <$text text={{{ [{FirstNumber}add{SecondNumber}] }}}/> ++ +title: FirstNumber +text: 2 ++ +title: SecondNumber +text: 2 diff --git a/editions/tw5.com/tiddlers/widgets/ActionListopsWidget.tid b/editions/tw5.com/tiddlers/widgets/ActionListopsWidget.tid index 3771ab445..ec9faf68b 100644 --- a/editions/tw5.com/tiddlers/widgets/ActionListopsWidget.tid +++ b/editions/tw5.com/tiddlers/widgets/ActionListopsWidget.tid @@ -1,6 +1,6 @@ caption: action-listops created: 20141025120850184 -modified: 20230805103548113 +modified: 20240509135041526 myfield: tags: ActionWidgets Widgets title: ActionListopsWidget @@ -35,10 +35,12 @@ The above widget will toggle the presence of the element <<.value "List Item">> Similarly, if an element is to always be removed when it is present, the `-` / `:except` [[filter run prefix|Filter Expression]] can be used. Both of the following yield the same result: ``` -<$action-listops $subfilter="-[[List Item]]"/> -<$action-listops $subfilter="+[remove[List Item]]"/> +<$action-listops $subfilter="-[[ListItem]]"/> +<$action-listops $subfilter="+[remove[ListItem]]"/> ``` +<<.infoBox """Note that the parameter of the [[remove Operator]] is a [[Title List]]. To remove one or more titles containing spaces the individual titles must be wrapped in double square brackets, usually via a soft [[Filter Parameter]]. See //Filtered List Variable Assignment// in the [[SetWidget]] documentation to learn more.""">> + Without any prefixes, the filter run output is simply [[dominantly appended|Dominant Append]] to the list. See also the [[Examples|ActionListopsWidget (Examples)]]. diff --git a/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid b/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid index a73403890..608a964d6 100644 --- a/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid +++ b/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid @@ -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. -! Test Czase Template Variables +! Test Case Template Variables The <<.wid testcase>> widget makes the following variables available within the rendered template: diff --git a/languages/zh-Hans/Fields.multids b/languages/zh-Hans/Fields.multids index b406a56ad..50a37b325 100644 --- a/languages/zh-Hans/Fields.multids +++ b/languages/zh-Hans/Fields.multids @@ -30,6 +30,7 @@ name: 具可读性的插件条目的名称 parent-plugin: 对于一个插件,指定其为哪个插件的子插件 plugin-priority: 插件条目的优先级数值 plugin-type: 插件条目的类型 +stability: 插件的开发状态:已弃用、实验性、稳定或旧版 released: TiddlyWiki 的发布日期 revision: 条目存放于服务器中的修订版本 source: 条目的网址 diff --git a/languages/zh-Hant/Fields.multids b/languages/zh-Hant/Fields.multids index a41e8b65e..74e5383a5 100644 --- a/languages/zh-Hant/Fields.multids +++ b/languages/zh-Hant/Fields.multids @@ -30,6 +30,7 @@ name: 具可讀性的套件條目的名稱 parent-plugin: 對於一個插件,指定其為哪個插件的子插件 plugin-priority: 套件條目的優先級數值 plugin-type: 套件條目的類型 +stability: 插件的開發狀態:已棄用、實驗性、穩定或舊版 released: TiddlyWiki 的釋出日期 revision: 條目存放於伺服器中的修訂版本 source: 條目的網址 diff --git a/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js b/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js index e22fe7378..90d4768e4 100644 --- a/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js +++ b/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js @@ -34,23 +34,22 @@ describe("Wiki-based tests", function() { if(!wiki.tiddlerExists("Output")) { throw "Missing 'Output' tiddler"; } - if(!wiki.tiddlerExists("ExpectedResult")) { - throw "Missing 'ExpectedResult' tiddler"; + if(wiki.tiddlerExists("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")); } - // 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")); }); });