diff --git a/core/images/new-journal-button.tid b/core/images/new-journal-button.tid
index 3b04d5786..5b793deb5 100755
--- a/core/images/new-journal-button.tid
+++ b/core/images/new-journal-button.tid
@@ -1,6 +1,4 @@
title: $:/core/images/new-journal-button
tags: $:/tags/Image
-<$parameters size="22pt" day=<>>
-> height=<> class="tc-image-new-journal-button tc-image-button" viewBox="0 0 128 128"><$text text=<>/>
-$parameters>
\ No newline at end of file
+<$parameters size="22pt" day=<>>> height=<> class="tc-image-new-journal-button tc-image-button" viewBox="0 0 128 128"><$text text=<>/> $parameters>
\ No newline at end of file
diff --git a/core/modules/startup/rootwidget.js b/core/modules/startup/rootwidget.js
index f5d90afb5..716275cda 100644
--- a/core/modules/startup/rootwidget.js
+++ b/core/modules/startup/rootwidget.js
@@ -38,6 +38,7 @@ exports.startup = function() {
url: params.url,
method: params.method,
body: params.body,
+ binary: params.binary,
oncompletion: params.oncompletion,
onprogress: params.onprogress,
bindStatus: params["bind-status"],
diff --git a/core/modules/utils/dom/http.js b/core/modules/utils/dom/http.js
index 5b1f0abe6..083381d8d 100644
--- a/core/modules/utils/dom/http.js
+++ b/core/modules/utils/dom/http.js
@@ -90,6 +90,7 @@ wiki: wiki to be used for executing action strings
url: URL for request
method: method eg GET, POST
body: text of request body
+binary: set to "yes" to force binary processing of response payload
oncompletion: action string to be invoked on completion
onprogress: action string to be invoked on progress updates
bindStatus: optional title of tiddler to which status ("pending", "complete", "error") should be written
@@ -110,6 +111,7 @@ function HttpClientRequest(options) {
this.bindProgress = options["bindProgress"];
this.method = options.method || "GET";
this.body = options.body || "";
+ this.binary = options.binary || "";
this.variables = options.variables;
var url = options.url;
$tw.utils.each(options.queryStrings,function(value,name) {
@@ -156,6 +158,8 @@ HttpClientRequest.prototype.send = function(callback) {
type: this.method,
headers: this.requestHeaders,
data: this.body,
+ returnProp: this.binary === "" ? "responseText" : "response",
+ responseType: this.binary === "" ? "text" : "arraybuffer",
callback: function(err,data,xhr) {
var hasSucceeded = xhr.status >= 200 && xhr.status < 300,
completionCode = hasSucceeded ? "complete" : "error",
@@ -175,6 +179,16 @@ HttpClientRequest.prototype.send = function(callback) {
data: (data || "").toString(),
headers: JSON.stringify(headers)
};
+ /* Convert data from binary to base64 */
+ if (xhr.responseType === "arraybuffer") {
+ var binary = "",
+ bytes = new Uint8Array(data),
+ len = bytes.byteLength;
+ for (var i=0; i widgets from each tiddler
$tw.utils.each(this.tiddlerList,function(title) {
- var parser = widgetPointer.wiki.parseTiddler(title,{parseAsInline:true});
+ var parser = widgetPointer.wiki.parseTiddler(title,{parseAsInline:true, configTrimWhiteSpace:true});
if(parser) {
var parseTreeNode = parser.tree[0];
while(parseTreeNode && ["setvariable","set","parameters"].indexOf(parseTreeNode.type) !== -1) {
diff --git a/core/modules/widgets/transclude.js b/core/modules/widgets/transclude.js
index 7e63ff156..7b4b9581d 100755
--- a/core/modules/widgets/transclude.js
+++ b/core/modules/widgets/transclude.js
@@ -41,16 +41,17 @@ TranscludeWidget.prototype.execute = function() {
this.collectAttributes();
this.collectStringParameters();
this.collectSlotFillParameters();
- // Get the parse tree nodes that we are transcluding
+ // Get the target text and parse tree nodes that we are transcluding
var target = this.getTransclusionTarget(),
- parseTreeNodes = target.parseTreeNodes;
+ parseTreeNodes;
this.sourceText = target.text;
this.parserType = 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
+ // Return the parse tree nodes
+ parseTreeNodes = target.parseTreeNodes;
break;
case "text/raw":
// Just return the raw text
@@ -158,7 +159,7 @@ TranscludeWidget.prototype.collectSlotFillParameters = function() {
};
/*
-Get transcluded parse tree nodes as an object {parser:,text:,type:}
+Get transcluded parse tree nodes as an object {text:,type:,parseTreeNodes:,parseAsInline:}
*/
TranscludeWidget.prototype.getTransclusionTarget = function() {
var self = this;
@@ -270,7 +271,6 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
// Return the parse tree
if(parser) {
return {
- parser: parser,
parseTreeNodes: parser.tree,
parseAsInline: parseAsInline,
text: parser.source,
@@ -279,7 +279,6 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
} 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,
diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js
index 1e6beae25..3b9a1de25 100755
--- a/core/modules/widgets/widget.js
+++ b/core/modules/widgets/widget.js
@@ -13,7 +13,7 @@ Widget base class
"use strict";
/* Maximum permitted depth of the widget tree for recursion detection */
-var MAX_WIDGET_TREE_DEPTH = 1000;
+var MAX_WIDGET_TREE_DEPTH = 500;
/*
Create a widget object for a parse tree node
diff --git a/core/modules/wiki.js b/core/modules/wiki.js
index 93e818f21..3eae3902d 100755
--- a/core/modules/wiki.js
+++ b/core/modules/wiki.js
@@ -1086,7 +1086,7 @@ exports.getSubstitutedText = function(text,widget,options) {
output = $tw.utils.replaceString(output,new RegExp("\\$" + $tw.utils.escapeRegExp(substitute.name) + "\\$","mg"),substitute.value);
});
// Substitute any variable references with their values
- return output.replace(/\$\((\w+)\)\$/g, function(match,varname) {
+ return output.replace(/\$\(([^\)\$]+)\)\$/g, function(match,varname) {
return widget.getVariable(varname,{defaultValue: ""})
});
};
diff --git a/core/ui/AlertTemplate.tid b/core/ui/AlertTemplate.tid
index ae15818a0..d67586b8d 100644
--- a/core/ui/AlertTemplate.tid
+++ b/core/ui/AlertTemplate.tid
@@ -1,3 +1,4 @@
+code-body: yes
title: $:/core/ui/AlertTemplate
\whitespace trim
diff --git a/core/ui/EditTemplate.tid b/core/ui/EditTemplate.tid
index 5aed61a73..6ad84a139 100644
--- a/core/ui/EditTemplate.tid
+++ b/core/ui/EditTemplate.tid
@@ -1,3 +1,4 @@
+code-body: yes
title: $:/core/ui/EditTemplate
\define delete-edittemplate-state-tiddlers()
diff --git a/core/ui/ImportPreviews/Text.tid b/core/ui/ImportPreviews/Text.tid
index 7832eb8b8..b37c109ad 100644
--- a/core/ui/ImportPreviews/Text.tid
+++ b/core/ui/ImportPreviews/Text.tid
@@ -1,5 +1,6 @@
title: $:/core/ui/ImportPreviews/Text
tags: $:/tags/ImportPreview
caption: {{$:/language/Import/Listing/Preview/Text}}
+code-body: yes
<$transclude tiddler=<> subtiddler=<> mode="block"/>
diff --git a/core/ui/PageStylesheet.tid b/core/ui/PageStylesheet.tid
index 0b32df5f8..f21909f09 100644
--- a/core/ui/PageStylesheet.tid
+++ b/core/ui/PageStylesheet.tid
@@ -1,4 +1,5 @@
title: $:/core/ui/PageStylesheet
+code-body: yes
\import [subfilter{$:/core/config/GlobalImportFilter}]
\whitespace trim
diff --git a/core/ui/PageTemplate.tid b/core/ui/PageTemplate.tid
index f0ab4852a..38b4c915b 100644
--- a/core/ui/PageTemplate.tid
+++ b/core/ui/PageTemplate.tid
@@ -2,6 +2,7 @@ title: $:/core/ui/PageTemplate
name: {{$:/language/PageTemplate/Name}}
description: {{$:/language/PageTemplate/Description}}
icon: $:/core/images/layout-button
+code-body: yes
\whitespace trim
\import [subfilter{$:/core/config/GlobalImportFilter}]
diff --git a/core/ui/RootTemplate.tid b/core/ui/RootTemplate.tid
index 1fd7319ba..4a7443c79 100644
--- a/core/ui/RootTemplate.tid
+++ b/core/ui/RootTemplate.tid
@@ -1,4 +1,5 @@
title: $:/core/ui/RootTemplate
+code-body: yes
<$transclude tiddler={{{ [{$:/layout}has[text]] ~[[$:/core/ui/PageTemplate]] }}} mode="inline"/>
diff --git a/core/ui/StoryTiddlerTemplate.tid b/core/ui/StoryTiddlerTemplate.tid
index 7cc26a849..a2b2f5558 100644
--- a/core/ui/StoryTiddlerTemplate.tid
+++ b/core/ui/StoryTiddlerTemplate.tid
@@ -1,3 +1,4 @@
title: $:/core/ui/StoryTiddlerTemplate
+code-body: yes
<$transclude tiddler={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/StoryTiddlerTemplateFilter]!is[draft]get[text]] :and[has[title]else[$:/core/ui/ViewTemplate]] }}} />
diff --git a/core/ui/ViewTemplate.tid b/core/ui/ViewTemplate.tid
index dcba5c953..9fa67816e 100644
--- a/core/ui/ViewTemplate.tid
+++ b/core/ui/ViewTemplate.tid
@@ -1,4 +1,5 @@
title: $:/core/ui/ViewTemplate
+code-body: yes
\whitespace trim
\define folded-state()
diff --git a/core/ui/ViewTemplate/body/default.tid b/core/ui/ViewTemplate/body/default.tid
index 083684879..5416c6e07 100644
--- a/core/ui/ViewTemplate/body/default.tid
+++ b/core/ui/ViewTemplate/body/default.tid
@@ -1,4 +1,5 @@
title: $:/core/ui/ViewTemplate/body/default
+code-body: yes
<$transclude>
diff --git a/core/wiki/config/ViewTemplateBodyFilters.multids b/core/wiki/config/ViewTemplateBodyFilters.multids
index 6348cc036..ff9fe7250 100644
--- a/core/wiki/config/ViewTemplateBodyFilters.multids
+++ b/core/wiki/config/ViewTemplateBodyFilters.multids
@@ -2,7 +2,8 @@ title: $:/config/ViewTemplateBodyFilters/
tags: $:/tags/ViewTemplateBodyFilter
stylesheet: [tag[$:/tags/Stylesheet]then[$:/core/ui/ViewTemplate/body/rendered-plain-text]]
-system: [prefix[$:/boot/]] [prefix[$:/config/]] [prefix[$:/core/macros]] [prefix[$:/core/save/]] [prefix[$:/core/templates/]] [prefix[$:/core/ui/]split[/]count[]compare:number:eq[4]] [prefix[$:/info/]] [prefix[$:/language/]] [prefix[$:/languages/]] [prefix[$:/snippets/]] [prefix[$:/state/]] [prefix[$:/status/]] [prefix[$:/info/]] [prefix[$:/temp/]] +[!is[image]limit[1]then[$:/core/ui/ViewTemplate/body/code]]
+core-ui-tags: [tag[$:/tags/PageTemplate]] [tag[$:/tags/EditTemplate]] [tag[$:/tags/ViewTemplate]] [tag[$:/tags/KeyboardShortcut]] [tag[$:/tags/ImportPreview]] [tag[$:/tags/EditPreview]][tag[$:/tags/EditorToolbar]] [tag[$:/tags/Actions]] :then[[$:/core/ui/ViewTemplate/body/code]]
+system: [prefix[$:/boot/]] [prefix[$:/config/]] [prefix[$:/core/macros]] [prefix[$:/core/save/]] [prefix[$:/core/templates/]] [prefix[$:/info/]] [prefix[$:/language/]] [prefix[$:/languages/]] [prefix[$:/snippets/]] [prefix[$:/state/]] [prefix[$:/status/]] [prefix[$:/info/]] [prefix[$:/temp/]] +[!is[image]limit[1]then[$:/core/ui/ViewTemplate/body/code]]
code-body: [field:code-body[yes]then[$:/core/ui/ViewTemplate/body/code]]
import: [field:plugin-type[import]then[$:/core/ui/ViewTemplate/body/import]]
plugin: [has[plugin-type]then[$:/core/ui/ViewTemplate/body/plugin]]
diff --git a/core/wiki/tags/ViewTemplateBodyFilter.tid b/core/wiki/tags/ViewTemplateBodyFilter.tid
index ab7ff262a..7b9fb7fd8 100644
--- a/core/wiki/tags/ViewTemplateBodyFilter.tid
+++ b/core/wiki/tags/ViewTemplateBodyFilter.tid
@@ -1,3 +1,2 @@
title: $:/tags/ViewTemplateBodyFilter
-list: $:/config/ViewTemplateBodyFilters/hide-body $:/config/ViewTemplateBodyFilters/code-body $:/config/ViewTemplateBodyFilters/stylesheet $:/config/ViewTemplateBodyFilters/system $:/config/ViewTemplateBodyFilters/import $:/config/ViewTemplateBodyFilters/plugin $:/config/ViewTemplateBodyFilters/default
-
+list: $:/config/ViewTemplateBodyFilters/hide-body $:/config/ViewTemplateBodyFilters/code-body $:/config/ViewTemplateBodyFilters/stylesheet $:/config/ViewTemplateBodyFilters/core-ui-advanced-search $:/config/ViewTemplateBodyFilters/core-ui-tags $:/config/ViewTemplateBodyFilters/system $:/config/ViewTemplateBodyFilters/import $:/config/ViewTemplateBodyFilters/plugin $:/config/ViewTemplateBodyFilters/default
\ No newline at end of file
diff --git a/editions/test/tiddlers/tests/data/importvariables/WithSetWidgets.tid b/editions/test/tiddlers/tests/data/importvariables/WithSetWidgets.tid
new file mode 100644
index 000000000..5d351583e
--- /dev/null
+++ b/editions/test/tiddlers/tests/data/importvariables/WithSetWidgets.tid
@@ -0,0 +1,23 @@
+title: ImportVariables/WithSetWidgets
+description: Import variables defined with a set widget
+type: text/vnd.tiddlywiki-multiple
+tags: [[$:/tags/wiki-test-spec]]
+
+title: Output
+
+\whitespace trim
+\import Definitions
+<$text text=<>/>,
+<$text text=<>/>
++
+title: Definitions
+
+\whitespace trim
+<$set name="one" value="elephant">
+<$set name="two" value="giraffe">
+$set>
+$set>
++
+title: ExpectedResult
+
+elephant,giraffe
\ No newline at end of file
diff --git a/editions/test/tiddlers/tests/data/importvariables/WithSetWidgets2.tid b/editions/test/tiddlers/tests/data/importvariables/WithSetWidgets2.tid
new file mode 100644
index 000000000..23fa58c57
--- /dev/null
+++ b/editions/test/tiddlers/tests/data/importvariables/WithSetWidgets2.tid
@@ -0,0 +1,22 @@
+title: ImportVariables/WithSetWidgets2
+description: Import variables defined with a set widget without whitespace pragma
+type: text/vnd.tiddlywiki-multiple
+tags: [[$:/tags/wiki-test-spec]]
+
+title: Output
+
+\whitespace trim
+\import Definitions
+<$text text=<>/>,
+<$text text=<>/>
++
+title: Definitions
+
+<$set name="one" value="elephant">
+<$set name="two" value="giraffe">
+$set>
+$set>
++
+title: ExpectedResult
+
+elephant,giraffe
\ No newline at end of file
diff --git a/editions/test/tiddlers/tests/data/importvariables/WithSetWidgetsAndMacros.tid b/editions/test/tiddlers/tests/data/importvariables/WithSetWidgetsAndMacros.tid
new file mode 100644
index 000000000..eaa81f38c
--- /dev/null
+++ b/editions/test/tiddlers/tests/data/importvariables/WithSetWidgetsAndMacros.tid
@@ -0,0 +1,29 @@
+title: ImportVariables/WithSetWidgetsAndMacros
+description: Import variables defined with a set widget without whitespace pragma
+type: text/vnd.tiddlywiki-multiple
+tags: [[$:/tags/wiki-test-spec]]
+
+title: Output
+
+\whitespace trim
+\import Definitions
+<$text text=<>/>,
+<$text text=<>/>,
+<$text text=<>/>,
+<$text text=<>/>
++
+title: Definitions
+
+\define name() Bugs Bunny
+\procedure address()
+Bunny Hill
+\end
+
+<$set name="one" value="elephant">
+<$set name="two" value="giraffe">
+$set>
+$set>
++
+title: ExpectedResult
+
+Bugs Bunny,Bunny Hill,elephant,giraffe
\ No newline at end of file
diff --git a/editions/test/tiddlers/tests/data/widgets/SubstitutedAttributes.tid b/editions/test/tiddlers/tests/data/widgets/SubstitutedAttributes.tid
index 408d202c6..9d5538573 100644
--- a/editions/test/tiddlers/tests/data/widgets/SubstitutedAttributes.tid
+++ b/editions/test/tiddlers/tests/data/widgets/SubstitutedAttributes.tid
@@ -6,14 +6,16 @@ tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
-<$let project="TiddlyWiki" disabled="true">
+<$set name="var with spaces" value="spaces">
+<$let project="TiddlyWiki" disabled="true" var-with-dashes="dashes">
+${ [[Hello]addsuffix[There]] }$` attrib=`myvalue` otherattrib=`$(1)$` blankattrib=`` quoted="here" disabled=```$(disabled)$``` dashes=`$(var-with-dashes)$` spaces=`$(var with spaces)$`>
$let>
+$set>
+
title: ExpectedResult
\ No newline at end of file
+HelloThere" dashes="dashes" disabled="true" otherattrib="" quoted="here" spaces="spaces">
\ No newline at end of file
diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Random Dog.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Random Dog.tid
new file mode 100644
index 000000000..8a6280fd8
--- /dev/null
+++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Random Dog.tid
@@ -0,0 +1,88 @@
+title: WidgetMessage: tm-http-request Example - Random Dog
+tags: $:/tags/Global
+
+\procedure download-dog(url)
+
+\procedure completion-download-dog()
+\import [subfilter{$:/core/config/GlobalImportFilter}]
+ <$action-log msg="In completion-download-dog"/>
+ <$action-log/>
+
+ <$list filter="[compare:number:gteq[200]compare:number:lteq[299]]" variable="ignore">
+
+ <$action-createtiddler
+ $basetitle=`$:/RandomDog/$(title)$`
+ text=<>
+ tags="$:/tags/RandomDog"
+ type={{{ [jsonget[content-type]] }}}
+ credits="https://random.dog/"
+ >
+ <$action-log msg="Created tiddler" title=<>/>
+ $createtiddler>
+ $list>
+\end completion-download-dog
+
+<$action-sendmessage
+ $message="tm-http-request"
+ url=<>
+ method="GET"
+ binary="yes"
+ oncompletion=<>
+ var-title=<>
+/>
+\end download-dog
+
+\procedure get-random-dog()
+
+\procedure completion-get-json()
+\import [subfilter{$:/core/config/GlobalImportFilter}]
+ <$action-log msg="In completion-get-json"/>
+ <$action-log/>
+
+ <$list filter="[compare:number:gteq[200]compare:number:lteq[299]]" variable="ignore">
+
+ <$macrocall $name="download-dog" url={{{ [jsonget[url]] }}}/>
+ $list>
+\end completion-get-json
+
+<$action-sendmessage
+ $message="tm-http-request"
+ url="https://random.dog/woof.json"
+ method="GET"
+ oncompletion=<>
+/>
+\end get-random-dog
+
+!! Random Dogs
+
+This demo uses the API of the website https://random.dog/ to import a random dog image or video.
+
+<$button actions=<>>
+Import a random dog image or video
+$button>
+
+<$list filter="[tag[$:/tags/RandomDog]limit[1]]" variable="ignore">
+
+!! Imported Tiddlers
+
+<$button>
+<$action-deletetiddler $filter="[tag[$:/tags/RandomDog]]"/>
+Delete all imported random dogs
+$button>
+
+Export all imported random dogs: <$macrocall $name="exportButton" exportFilter="[tag[$:/tags/RandomDog]]" lingoBase="$:/language/Buttons/ExportTiddlers/"/>
+
+$list>
+
+
+<$list filter="[tag[$:/tags/RandomDog]!sort[modified]]">
+
+<$link>
+<$text text=<>/>
+$link>
+
+<$transclude $tiddler=<>/>
+
+
+$list>
+
diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Zotero.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Zotero.tid
index 472f0abb0..c26eb9895 100644
--- a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Zotero.tid
+++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Zotero.tid
@@ -1,5 +1,5 @@
title: WidgetMessage: tm-http-request Example - Zotero
-tags: $:/tags/Macro
+tags: $:/tags/Global
\procedure select-zotero-group()
Specify the Zotero group ID to import
@@ -34,7 +34,7 @@ Specify the Zotero group ID to import
\procedure zotero-get-items(start:"0",limit:"25")
\procedure completion()
-\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]
+\import [subfilter{$:/core/config/GlobalImportFilter}]
<$action-log msg="In completion"/>
<$action-log/>
diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request.tid
index f6c82e760..9c441c524 100644
--- a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request.tid
+++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request.tid
@@ -1,6 +1,6 @@
caption: tm-http-request
created: 20230429161453032
-modified: 20230429161453032
+modified: 20230717104212742
tags: Messages
title: WidgetMessage: tm-http-request
type: text/vnd.tiddlywiki
@@ -18,6 +18,7 @@ The following parameters are used:
|!Name |!Description |
|method |HTTP method (eg "GET", "POST") |
|body |String data to be sent with the request |
+|binary |<<.from-version "5.3.1">> Set to "yes" to cause the response body to be treated as binary data and returned in base64 format |
|query-* |Query string parameters with string values |
|header-* |Headers with string values |
|password-header-* |Headers with values taken from the password store |
@@ -49,3 +50,4 @@ Note that the state tiddler $:/state/http-requests contains a number representin
!! Examples
* [[Zotero's|https://www.zotero.org/]] API for retrieving reference items: [[WidgetMessage: tm-http-request Example - Zotero]]
+* [[Random Dog's|https://random.dog/]] API for retrieving random pictures of dogs showing how to retrieve binary data: [[WidgetMessage: tm-http-request Example - Random Dogs]]