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=<>/> - \ 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=<>/> \ 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"> + + ++ +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"> + + ++ +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"> + + ++ +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)$`>
+ + 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=<>/> + + +\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]] }}}/> + +\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 + + +<$list filter="[tag[$:/tags/RandomDog]limit[1]]" variable="ignore"> + +!! Imported Tiddlers + +<$button> +<$action-deletetiddler $filter="[tag[$:/tags/RandomDog]]"/> +Delete all imported random dogs + + +Export all imported random dogs: <$macrocall $name="exportButton" exportFilter="[tag[$:/tags/RandomDog]]" lingoBase="$:/language/Buttons/ExportTiddlers/"/> + + + +
    +<$list filter="[tag[$:/tags/RandomDog]!sort[modified]]"> +
  1. +<$link> +<$text text=<>/> + +
    +<$transclude $tiddler=<>/> +
    +
  2. + +
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]]