From 48b22abdaab62c281c207127c66883b50898f9dd Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Fri, 2 Jun 2023 10:41:42 +0100 Subject: [PATCH 01/94] Add a warning for tiddlywiki.info or plugin.info having json errors --- boot/boot.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index a9fb91b74..58c06b566 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -2080,7 +2080,11 @@ $tw.loadPluginFolder = function(filepath,excludeRegExp) { console.log("Warning: missing plugin.info file in " + filepath); return null; } - var pluginInfo = $tw.utils.parseJSONSafe(fs.readFileSync(infoPath,"utf8")); + var pluginInfo = $tw.utils.parseJSONSafe(fs.readFileSync(infoPath,"utf8"),function() {return null;}); + if(!pluginInfo) { + console.log("warning: invalid JSON in plugin.info file at " + infoPath); + pluginInfo = {}; + } // Read the plugin files var pluginFiles = $tw.loadTiddlersFromPath(filepath,excludeRegExp); // Save the plugin tiddlers into the plugin info @@ -2197,7 +2201,11 @@ $tw.loadWikiTiddlers = function(wikiPath,options) { pluginFields; // Bail if we don't have a wiki info file if(fs.existsSync(wikiInfoPath)) { - wikiInfo = $tw.utils.parseJSONSafe(fs.readFileSync(wikiInfoPath,"utf8")); + wikiInfo = $tw.utils.parseJSONSafe(fs.readFileSync(wikiInfoPath,"utf8"),function() {return null;}); + if(!wikiInfo) { + console.log("warning: invalid JSON in tiddlywiki.info file at " + wikiInfoPath); + wikiInfo = {}; + } } else { return null; } From d83d8e724575f9aba463d49d7de02014010ebc20 Mon Sep 17 00:00:00 2001 From: Mario Pietsch Date: Sat, 3 Jun 2023 15:27:59 +0200 Subject: [PATCH 02/94] Cover stand alone .from-version pill in a HTML block-element (#7512) --- editions/tw5.com/tiddlers/system/operator-template.tid | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editions/tw5.com/tiddlers/system/operator-template.tid b/editions/tw5.com/tiddlers/system/operator-template.tid index 7d7ba9311..4d7abc334 100644 --- a/editions/tw5.com/tiddlers/system/operator-template.tid +++ b/editions/tw5.com/tiddlers/system/operator-template.tid @@ -1,6 +1,6 @@ created: 20150203173506000 list-before: $:/core/ui/ViewTemplate/body -modified: 20220316121232243 +modified: 20230602181119360 tags: $:/tags/ViewTemplate title: $:/editions/tw5.com/operator-template @@ -72,10 +72,10 @@ title: $:/editions/tw5.com/operator-template -[[Learn more about how to use Filters|Filters]] +

[[Learn more about how to use Filters|Filters]]

<$list filter="[all[current]has[from-version]]" variable="listItem"> -<$macrocall $name=".from-version" version={{!!from-version}}/> +

<$macrocall $name=".from-version" version={{!!from-version}}/>

From 2221b8e08a572b4899081cb86e7f9a1dd57adf11 Mon Sep 17 00:00:00 2001 From: Saq Imtiaz Date: Sat, 3 Jun 2023 15:33:10 +0200 Subject: [PATCH 03/94] Adds a deserialize filter operator (#7511) * feat: added deserialize operator, tests and documentation * fix: correct typo in lingo file * fix: remove test that fails on node but succeeds in browser due to different availability of DOM deserializer --- core/language/en-GB/Misc.multids | 2 + core/modules/filters/deserialize.js | 39 ++++++++++++++++ .../tests/data/deserializers/case 6.tid | 8 ++++ .../tests/test-deserialize-operator.js | 44 +++++++++++++++++++ .../tiddlers/filters/deserialize Operator.tid | 26 +++++++++++ .../deserialize Operator (Examples).tid | 29 ++++++++++++ 6 files changed, 148 insertions(+) create mode 100644 core/modules/filters/deserialize.js create mode 100644 editions/test/tiddlers/tests/data/deserializers/case 6.tid create mode 100644 editions/test/tiddlers/tests/test-deserialize-operator.js create mode 100644 editions/tw5.com/tiddlers/filters/deserialize Operator.tid create mode 100644 editions/tw5.com/tiddlers/filters/examples/deserialize Operator (Examples).tid diff --git a/core/language/en-GB/Misc.multids b/core/language/en-GB/Misc.multids index 52545bd86..2c10d1acb 100644 --- a/core/language/en-GB/Misc.multids +++ b/core/language/en-GB/Misc.multids @@ -25,6 +25,8 @@ Encryption/RepeatPassword: Repeat password Encryption/PasswordNoMatch: Passwords do not match Encryption/SetPassword: Set password Error/Caption: Error +Error/DeserializeOperator/MissingOperand: Filter Error: Missing operand for 'deserialize' operator +Error/DeserializeOperator/UnknownDeserializer: Filter Error: Unknown deserializer provided as operand for the 'deserialize' operator Error/Filter: Filter error Error/FilterSyntax: Syntax error in filter expression Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run diff --git a/core/modules/filters/deserialize.js b/core/modules/filters/deserialize.js new file mode 100644 index 000000000..5511f29e8 --- /dev/null +++ b/core/modules/filters/deserialize.js @@ -0,0 +1,39 @@ +/*\ +title: $:/core/modules/filters/deserialize.js +type: application/javascript +module-type: filteroperator +Filter operator for deserializing string data into JSON representing tiddlers +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +exports["deserialize"] = function(source,operator,options) { + var results = [], + deserializer; + if(operator.operand) { + // Get the deserializer identified by the operand + deserializer = $tw.Wiki.tiddlerDeserializerModules[operator.operand]; + if(deserializer) { + source(function(tiddler,title) { + var tiddlers; + try { + tiddlers = deserializer(title); + } catch(e) { + // Return an empty array if we could not extract any tiddlers + tiddlers = []; + } + results.push(JSON.stringify(tiddlers)); + }); + } else { + return [$tw.language.getString("Error/DeserializeOperator/UnknownDeserializer")]; + } + } else { + return [$tw.language.getString("Error/DeserializeOperator/MissingOperand")]; + } + return results; +} + +})(); \ No newline at end of file diff --git a/editions/test/tiddlers/tests/data/deserializers/case 6.tid b/editions/test/tiddlers/tests/data/deserializers/case 6.tid new file mode 100644 index 000000000..b6e653c39 --- /dev/null +++ b/editions/test/tiddlers/tests/data/deserializers/case 6.tid @@ -0,0 +1,8 @@ +title: dezerializer test data case 6 +type: application/json + +[ + {"created":"20230601125557184","text":"Before you start storing important information in ~TiddlyWiki it is vital to make sure that you can reliably save changes. See https://tiddlywiki.com/#GettingStarted for details\n\n","title":"GettingStarted","modified":"20230601125601619"}, + {"created":"20230601125507054","text":"Welcome to \"TiddlyWiki\".\n\nThis is a test tiddler.","tags":"","title":"Hello There \"Welcome\"","modified":"20230601125551144"}, + {"title":"TiddlyWiki","created":"20130822170700000","modified":"20170127221451610","tags":"Concepts","type":"text/vnd.tiddlywiki","text":"~TiddlyWiki is a rich, interactive tool for manipulating complex data with structure that doesn't easily fit into conventional tools like spreadsheets or wordprocessors.\n\n~TiddlyWiki is designed to fit around your brain, helping you deal with the things that won't fit."} +] diff --git a/editions/test/tiddlers/tests/test-deserialize-operator.js b/editions/test/tiddlers/tests/test-deserialize-operator.js new file mode 100644 index 000000000..c629de3ae --- /dev/null +++ b/editions/test/tiddlers/tests/test-deserialize-operator.js @@ -0,0 +1,44 @@ +/*\ +title: test-deserialize-operator.js +type: application/javascript +tags: [[$:/tags/test-spec]] + +Tests deserialize[] filter operator with various core deserializers + +\*/ +(function(){ + + /* jslint node: true, browser: true */ + /* eslint-env node, browser, jasmine */ + /* eslint no-mixed-spaces-and-tabs: ["error", "smart-tabs"]*/ + /* global $tw, require */ + "use strict"; + + + describe("deserialize operator tests", function() { + + it("should support the deserialize[] operator", function() { + //Unknown deserializer as operand + expect($tw.wiki.filterTiddlers("[{dezerializer test data case 4}deserialize[unknown/deserializer]]")).toEqual([$tw.language.getString("Error/DeserializeOperator/UnknownDeserializer")]); + + //Missing operand + expect($tw.wiki.filterTiddlers("[{dezerializer test data case 4}deserialize[]]")).toEqual([$tw.language.getString("Error/DeserializeOperator/MissingOperand")]); + + //Deserialize TiddlyWiki file + expect($tw.wiki.filterTiddlers("[{dezerializer test data case 4}deserialize[text/html]]")).toEqual(['[{"type":"text/vnd.tiddlywiki","text":"Abacus","title":"Hello \\"There\\""},{"title":"Hello \\"There\\"","text":"Calculator"}]']); + expect($tw.wiki.filterTiddlers("[{dezerializer test data case 5}deserialize[text/html]]")).toEqual(['[{"type":"text/vnd.tiddlywiki","text":"Abacus","title":"Hello \\"There\\""},{"title":"Hello \\"There\\"","text":"Calculator"},{"title":"Hello \\"There\\"","text":"Protractor"}]']); + + // Deserialize JSON payload containing tiddlers + expect($tw.wiki.filterTiddlers("[{dezerializer test data case 6}deserialize[application/json]]")).toEqual( [ `[{"created":"20230601125557184","text":"Before you start storing important information in ~TiddlyWiki it is vital to make sure that you can reliably save changes. See https://tiddlywiki.com/#GettingStarted for details\\n\\n","title":"GettingStarted","modified":"20230601125601619"},{"created":"20230601125507054","text":"Welcome to \\"TiddlyWiki\\".\\n\\nThis is a test tiddler.","tags":"","title":"Hello There \\"Welcome\\"","modified":"20230601125551144"},{"title":"TiddlyWiki","created":"20130822170700000","modified":"20170127221451610","tags":"Concepts","type":"text/vnd.tiddlywiki","text":"~TiddlyWiki is a rich, interactive tool for manipulating complex data with structure that doesn't easily fit into conventional tools like spreadsheets or wordprocessors.\\n\\n~TiddlyWiki is designed to fit around your brain, helping you deal with the things that won't fit."}]` ]); + expect($tw.wiki.filterTiddlers("[{dezerializer test data case 6}deserialize[application/json]jsonindexes[]] :map[{dezerializer test data case 6}jsonget,[title]]")).toEqual([ 'GettingStarted', 'Hello There "Welcome"', 'TiddlyWiki' ]); + + //Deserialize TiddlyWiki file with an mismatched deserializer + expect($tw.wiki.filterTiddlers("[{dezerializer test data case 5}deserialize[application/json]]")).toEqual([jasmine.stringMatching('JSON error')]); + }); + }); + +})(); + + + + \ No newline at end of file diff --git a/editions/tw5.com/tiddlers/filters/deserialize Operator.tid b/editions/tw5.com/tiddlers/filters/deserialize Operator.tid new file mode 100644 index 000000000..616e5ae19 --- /dev/null +++ b/editions/tw5.com/tiddlers/filters/deserialize Operator.tid @@ -0,0 +1,26 @@ +caption: deserialize +created: 20230601195749377 +from-version: 5.3.0 +modified: 20230602105513132 +op-input: a selection of strings +op-output: JSON representations of tiddlers extracted from input titles. +op-parameter: the deserializer module to be used to extract tiddlers from the input +op-purpose: extract JSON representation of tiddlers from the input strings +tags: [[Filter Operators]] [[Special Operators]] +title: deserialize Operator +type: text/vnd.tiddlywiki + +<<.tip "Deserializer modules parse text in various formats into their JSON representation as tiddlers. You can see the deserializers available in a wiki using the [[deserializers operator|deserializers Operator]].">> + +|!Deserializer |!Description | +|(DOM)|Extracts tiddlers from a DOM node, should not be used with the <<.op deserialize[]>> operator | +|application/javascript|Parses a JavaScript module as a tiddler extracting fields from the header comment| +|application/json|Parses [[JSON|JSON in TiddlyWiki]] into tiddlers| +|application/x-tiddler|Parses the [[.tid file format|TiddlerFiles]] as a tiddler| +|application/x-tiddler-html-div|Parses the [[
.tiddler file format|TiddlerFiles]] as a tiddler| +|application/x-tiddlers|Parses the [[MultiTiddlerFile format|MultiTiddlerFiles]] as tiddlers| +|text/css|Parses CSS as a tiddler extracting fields from the header comment| +|text/html|Parses an HTML file into tiddlers. Supports ~TiddlyWiki Classic HTML files, ~TiddlyWiki5 HTML files and ordinary HTML files| +|text/plain|Parses plain text as a tiddler| + +<<.operator-examples "deserialize">> \ No newline at end of file diff --git a/editions/tw5.com/tiddlers/filters/examples/deserialize Operator (Examples).tid b/editions/tw5.com/tiddlers/filters/examples/deserialize Operator (Examples).tid new file mode 100644 index 000000000..5170809b7 --- /dev/null +++ b/editions/tw5.com/tiddlers/filters/examples/deserialize Operator (Examples).tid @@ -0,0 +1,29 @@ +created: 20230601200356736 +modified: 20230602105036887 +tags: [[Operator Examples]] [[deserialize Operator]] +title: deserialize Operator (Examples) +type: text/vnd.tiddlywiki + +\define html-data() + + + + + Test Data + + + + + + + + +\end + +This example uses the predefined variable `html-data`: +<$codeblock code=<> language="HTML"/> + +<<.operator-example 1 "[deserialize[text/html]]">> From 88dc6eba9616191e00c3558d32734ed95833ed09 Mon Sep 17 00:00:00 2001 From: Bram Chen Date: Sun, 4 Jun 2023 01:00:37 +0800 Subject: [PATCH 04/94] Update chinese language files (#7514) * Add chinese error messages for 'deserialize' operator --- languages/zh-Hans/Misc.multids | 2 ++ languages/zh-Hant/Misc.multids | 2 ++ 2 files changed, 4 insertions(+) diff --git a/languages/zh-Hans/Misc.multids b/languages/zh-Hans/Misc.multids index 183a677a6..ce369efa8 100644 --- a/languages/zh-Hans/Misc.multids +++ b/languages/zh-Hans/Misc.multids @@ -25,6 +25,8 @@ Encryption/RepeatPassword: 重复输入密码 Encryption/PasswordNoMatch: 密码不匹配 Encryption/SetPassword: 设定密码 Error/Caption: 错误 +Error/DeserializeOperator/MissingOperand: 筛选器错误:'deserialize' 运算符缺少运算元 +Error/DeserializeOperator/UnknownDeserializer: 筛选器错误:未知的解串器被提供为 'deserialize' 运算符的操作数 Error/Filter: 筛选器错误 Error/FilterRunPrefix: 筛选器错误:筛选器 run 的未知首码 Error/FilterSyntax: 筛选器运算式中的语法错误 diff --git a/languages/zh-Hant/Misc.multids b/languages/zh-Hant/Misc.multids index e850ebaf9..e38900415 100644 --- a/languages/zh-Hant/Misc.multids +++ b/languages/zh-Hant/Misc.multids @@ -25,6 +25,8 @@ Encryption/RepeatPassword: 重複輸入密碼 Encryption/PasswordNoMatch: 密碼不匹配 Encryption/SetPassword: 設定密碼 Error/Caption: 錯誤 +Error/DeserializeOperator/MissingOperand: 篩選器錯誤:'deserialize' 運算子缺少運算元 +Error/DeserializeOperator/UnknownDeserializer: 篩選器錯誤:未知的解串器被提供為 'deserialize' 運算子的運算元 Error/Filter: 篩選器錯誤 Error/FilterRunPrefix: 篩選器錯誤:篩選器 run 的未知首碼 Error/FilterSyntax: 篩選器運算式中的語法錯誤 From f141cbf8a5d3cb79662c2ed6ae4e006e56ea6b34 Mon Sep 17 00:00:00 2001 From: twMat Date: Wed, 7 Jun 2023 16:26:47 +0200 Subject: [PATCH 05/94] Update WidgetMessage_ tm-close-all-windows.tid (#7525) added caption. The problem can be seen in list https://tiddlywiki.com/#Messages --- .../tiddlers/messages/WidgetMessage_ tm-close-all-windows.tid | 1 + 1 file changed, 1 insertion(+) diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-close-all-windows.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-close-all-windows.tid index d916460e9..75fbbfc09 100644 --- a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-close-all-windows.tid +++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-close-all-windows.tid @@ -3,6 +3,7 @@ modified: 20220301180818011 tags: Messages title: WidgetMessage: tm-close-all-windows type: text/vnd.tiddlywiki +caption: tm-close-all-windows <<.from-version 5.2.2>> The `tm-close-all-windows` [[message|Messages]] closes all additional //browser// window that were opened with [[tm-open-window|WidgetMessage: tm-open-window]]. From cce23ac6cddbccc88a848dcc5c456e57c01b2c20 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Thu, 8 Jun 2023 08:32:56 +0100 Subject: [PATCH 06/94] Fix size of buttons in editor toolbar dropdowns Fixes #7529 --- themes/tiddlywiki/vanilla/base.tid | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/themes/tiddlywiki/vanilla/base.tid b/themes/tiddlywiki/vanilla/base.tid index 724d0dae9..53943f994 100644 --- a/themes/tiddlywiki/vanilla/base.tid +++ b/themes/tiddlywiki/vanilla/base.tid @@ -1388,6 +1388,11 @@ html body.tc-body.tc-single-tiddler-window { height: 1.2em; } +.tc-editor-toolbar .tc-drop-down a, +.tc-editor-toolbar .tc-drop-down button { + padding: 0; +} + .tc-editor-toolbar button:hover { background-color: <>; fill: <>; From 7b9915b5c237a577bc6931cd1619d5a615b35f39 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Thu, 8 Jun 2023 21:18:24 +0100 Subject: [PATCH 07/94] Update release note --- editions/prerelease/tiddlers/Release 5.3.0.tid | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/editions/prerelease/tiddlers/Release 5.3.0.tid b/editions/prerelease/tiddlers/Release 5.3.0.tid index 714285932..cf01e8933 100644 --- a/editions/prerelease/tiddlers/Release 5.3.0.tid +++ b/editions/prerelease/tiddlers/Release 5.3.0.tid @@ -34,6 +34,7 @@ The new transclusion architecture is not by itself sufficient to enable us to fu * <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7260">> Dynannotate pugin to support three additional search modes * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7365">> problem with [[BrowserStorage Plugin]] unnecessarily saving shadow tiddlers +* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7493">> [[CodeMirror Plugin]] to add an option to make trailing spaces visible ! Translation improvement @@ -55,8 +56,10 @@ Improvements to the following translations: ! Filter improvements +* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7511"> new [[deserialize Operator]] for converting various textual representations of tiddlers into JSON data * <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7292">> [[format Operator]] to support converting Unix timestamps to TiddlyWiki's native date format + ! Hackability Improvements * <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7413">> [[Core Icons]] to allow the size to be controlled with a parameter @@ -73,6 +76,10 @@ Improvements to the following translations: * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7401">> bug whereby scrolling occurs if the linkcatcher widget triggers an action-navigate and the $scroll attribute is set to "no" * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7409">> problem switching between LTR and RTL text * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7448">> bug when checkbox widget's listField attribute was given the name of a date field (like <<.field created>> or <<.field modified>>) +* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7529">> size of buttons in dropdown for editor "link" toolbar button +* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/8e132948b6bec623d81d300fbe6dc3a0307bcc6d">> crash when transcluding a lazily loaded tiddler as an attribute value +* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7462">> DiffTextWidget crash with missing or empty attributes +* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7448">> CheckboxWidget to avoid writing to date fields ! Developer Improvements @@ -80,7 +87,9 @@ Improvements to the following translations: ! Node.js Improvements +* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7471">> [[WebServer Parameter: authenticated-user-header]] to require URI encoding of authenticated username header, permitting non-ASCII characters in usernames * <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7253">> support for `filepath` source attribute to [[tiddlywiki.files Files]] +* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/commit/48b22abdaab62c281c207127c66883b50898f9dd">> a warning message for JSON errors in [[tiddlywiki.info Files]] or [[plugin.info Files|PluginFolders]] ! Performance Improvements @@ -92,17 +101,22 @@ Improvements to the following translations: <<.contributors """ Arlen22 +BramChen btheado donmor flibbles GameDungeon +JoshuaFontany kookma linonetwo Marxsal +mateuszwilczek michsa muzimuzhi pmario rmunn saqimtiaz +tavin +twMat yaisog """>> From 92f720901dbf75d911319e03bfcfc188abe0ec95 Mon Sep 17 00:00:00 2001 From: Mario Pietsch Date: Thu, 8 Jun 2023 22:38:31 +0200 Subject: [PATCH 08/94] Add missing data-tag-title attributes where needed (#7530) * add missing data-tag-title assignments * docs for data-tag-title * fix typo in the docs * rename file --- core/ui/EditTemplate/tags.tid | 4 +-- core/ui/TagPickerTagTemplate.tid | 2 +- .../howtos/Custom tag pill styles.tid | 32 +++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 editions/tw5.com/tiddlers/howtos/Custom tag pill styles.tid diff --git a/core/ui/EditTemplate/tags.tid b/core/ui/EditTemplate/tags.tid index 8d829b30e..5084478b4 100644 --- a/core/ui/EditTemplate/tags.tid +++ b/core/ui/EditTemplate/tags.tid @@ -14,8 +14,8 @@ color:$(foregroundColor)$; \define tag-body-inner(colour,fallbackTarget,colourA,colourB,icon,tagField:"tags") \whitespace trim <$vars foregroundColor=<> backgroundColor="""$colour$"""> -> class="tc-tag-label tc-tag-list-item tc-small-gap-right"> -<$transclude tiddler="""$icon$"""/><$view field="title" format="text" /> +> class="tc-tag-label tc-tag-list-item tc-small-gap-right" data-tag-title=<>> +<$transclude tiddler="""$icon$"""/><$view field="title" format="text"/> <$button class="tc-btn-invisible tc-remove-tag-button" style=<>><$action-listops $tiddler=<> $field=<<__tagField__>> $subfilter="-[{!!title}]"/>{{$:/core/images/close-button}} diff --git a/core/ui/TagPickerTagTemplate.tid b/core/ui/TagPickerTagTemplate.tid index 9545725b3..6329f86ae 100644 --- a/core/ui/TagPickerTagTemplate.tid +++ b/core/ui/TagPickerTagTemplate.tid @@ -15,7 +15,7 @@ title: $:/core/ui/TagPickerTagTemplate <> <$set name="backgroundColor" value={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}}> <$wikify name="foregroundColor" text="""<$macrocall $name="contrastcolour" target=<> fallbackTarget=<> colourA=<> colourB=<>/>"""> ->> +> data-tag-title=<> > {{||$:/core/ui/TiddlerIcon}}<$view field="title" format="text"/> diff --git a/editions/tw5.com/tiddlers/howtos/Custom tag pill styles.tid b/editions/tw5.com/tiddlers/howtos/Custom tag pill styles.tid new file mode 100644 index 000000000..f7472e9b2 --- /dev/null +++ b/editions/tw5.com/tiddlers/howtos/Custom tag pill styles.tid @@ -0,0 +1,32 @@ +created: 20230608121519758 +modified: 20230608123444591 +tags: [[How to apply custom styles]] +title: Custom tag pill styles +type: text/vnd.tiddlywiki + +! Attribute: data-tag-title + +<<.from-version "5.2.0">> The attribute <<.attr data-tag-title>> was added to tag pills visible in the tiddler view template. + +<<.from-version "5.3.0">> The attribute was added to every tag pill visible in the standard ~TiddlyWiki UI. Especially the edit template tag list, the tag-picker dropdown, the Right sidebar -> More -> Tags tab and the $:/TagManager + +The <<.attr data-tag-title>> HTML attribute only contains the tag-title visible in the tag pill. It can be used to style the tag-pill. + +If you want to style the whole tiddler have a look at: [[Custom styles by data-tiddler-title]] + +!! Examples + +If you use the following CSS in a new tiddler tagged: `$:/tags/Stylesheet` every tag that starts with a `#` will have a new border radius. So those tags stand out in contrast to the default tags. + +''You have to define both CSS rules'', due to the existing UI structure to catch all tag-pills in the existing TW UI. + +``` +[data-tag-title^="#"] .tc-tag-label, +[data-tag-title^="#"].tc-tag-label { + border-radius: 3px; +} +``` + +!! More Possibilities + +{{Attribute Selectors}} From a66b04f532b1dd695531bc6076bf8263c25969ad Mon Sep 17 00:00:00 2001 From: WhiteFall <32425955+Zacharia2@users.noreply.github.com> Date: Fri, 9 Jun 2023 04:39:33 +0800 Subject: [PATCH 09/94] Signing the CLA (#7516) --- licenses/cla-individual.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/licenses/cla-individual.md b/licenses/cla-individual.md index ac868477f..9693779c5 100644 --- a/licenses/cla-individual.md +++ b/licenses/cla-individual.md @@ -531,3 +531,5 @@ Michelle Saad, @michsa, 2023-03-08 Carmine Guida, @carmineguida, 2023-05-17 Tavin Cole, @tavin, 2023/05/25 + +WhiteFall, @Zacharia2, 2023/06/04 From 0095ea60d9a5c8f8dd813c7a21c3a2fc7618a93b Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Thu, 8 Jun 2023 21:45:14 +0100 Subject: [PATCH 10/94] Switch off CamelCase linking by default (#7513) * Disable camelcase by default * New parse rule for ~CamelCase For backwards compatibility with text that includes ~ to suppress camelcase links * Enable CamelCase for main documentation wikis Will take us a bit longer to convert all the links over * Fix tests * Release note update --- .../wikiparser/rules/wikilinkprefix.js | 40 +++++++++++++++++++ core/wiki/config/wikilink.tid | 2 +- .../configWikiParserRulesInlineWikilink.tid | 3 ++ .../prerelease/tiddlers/Release 5.3.0.tid | 4 ++ .../configWikiParserRulesInlineWikilink.tid | 3 ++ editions/test/tiddlers/tests/test-filters.js | 20 +++++----- editions/test/tiddlers/tests/test-wikitext.js | 10 ----- .../configWikiParserRulesInlineWikilink.tid | 3 ++ 8 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 core/modules/parsers/wikiparser/rules/wikilinkprefix.js create mode 100644 editions/dev/tiddlers/system/configWikiParserRulesInlineWikilink.tid create mode 100644 editions/prerelease/tiddlers/system/configWikiParserRulesInlineWikilink.tid create mode 100644 editions/tw5.com/tiddlers/system/configWikiParserRulesInlineWikilink.tid diff --git a/core/modules/parsers/wikiparser/rules/wikilinkprefix.js b/core/modules/parsers/wikiparser/rules/wikilinkprefix.js new file mode 100644 index 000000000..60cb3d992 --- /dev/null +++ b/core/modules/parsers/wikiparser/rules/wikilinkprefix.js @@ -0,0 +1,40 @@ +/*\ +title: $:/core/modules/parsers/wikiparser/rules/wikilinkprefix.js +type: application/javascript +module-type: wikirule + +Wiki text inline rule for suppressed wiki links. For example: + +``` +~SuppressedLink +``` + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +exports.name = "wikilinkprefix"; +exports.types = {inline: true}; + +exports.init = function(parser) { + this.parser = parser; + // Regexp to match + this.matchRegExp = new RegExp($tw.config.textPrimitives.unWikiLink + $tw.config.textPrimitives.wikiLink,"mg"); +}; + +/* +Parse the most recent match +*/ +exports.parse = function() { + // Get the details of the match + var linkText = this.match[0]; + // Move past the wikilink + this.parser.pos = this.matchRegExp.lastIndex; + // Return the link without unwikilink character as plain text + return [{type: "text", text: linkText.substr(1)}]; +}; + +})(); diff --git a/core/wiki/config/wikilink.tid b/core/wiki/config/wikilink.tid index 9a395abd6..6cd5cd8cb 100644 --- a/core/wiki/config/wikilink.tid +++ b/core/wiki/config/wikilink.tid @@ -1,3 +1,3 @@ title: $:/config/WikiParserRules/Inline/wikilink -enable \ No newline at end of file +disable \ No newline at end of file diff --git a/editions/dev/tiddlers/system/configWikiParserRulesInlineWikilink.tid b/editions/dev/tiddlers/system/configWikiParserRulesInlineWikilink.tid new file mode 100644 index 000000000..9a395abd6 --- /dev/null +++ b/editions/dev/tiddlers/system/configWikiParserRulesInlineWikilink.tid @@ -0,0 +1,3 @@ +title: $:/config/WikiParserRules/Inline/wikilink + +enable \ No newline at end of file diff --git a/editions/prerelease/tiddlers/Release 5.3.0.tid b/editions/prerelease/tiddlers/Release 5.3.0.tid index cf01e8933..db7e3a3b9 100644 --- a/editions/prerelease/tiddlers/Release 5.3.0.tid +++ b/editions/prerelease/tiddlers/Release 5.3.0.tid @@ -30,6 +30,10 @@ These changes lay the groundwork for macros and related features to be deprecate The new transclusion architecture is not by itself sufficient to enable us to fully deprecate macros yet. To handle the remaining use cases we propose a new backtick quoted attribute format that allows for the substitution of variable values. See https://github.com/Jermolene/TiddlyWiki5/issues/6663 for details. +! Defaulting to Disabling CamelCase Links + +<<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/7513">> CamelCase linking is now disabled by default. (Note that this wiki has CamelCase linking explicitly enabled) + ! Plugin Improvements * <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7260">> Dynannotate pugin to support three additional search modes diff --git a/editions/prerelease/tiddlers/system/configWikiParserRulesInlineWikilink.tid b/editions/prerelease/tiddlers/system/configWikiParserRulesInlineWikilink.tid new file mode 100644 index 000000000..9a395abd6 --- /dev/null +++ b/editions/prerelease/tiddlers/system/configWikiParserRulesInlineWikilink.tid @@ -0,0 +1,3 @@ +title: $:/config/WikiParserRules/Inline/wikilink + +enable \ No newline at end of file diff --git a/editions/test/tiddlers/tests/test-filters.js b/editions/test/tiddlers/tests/test-filters.js index 49a790166..1ffc73f17 100644 --- a/editions/test/tiddlers/tests/test-filters.js +++ b/editions/test/tiddlers/tests/test-filters.js @@ -99,14 +99,14 @@ Tests the filtering mechanism. }, "TiddlerSix": { title: "TiddlerSix", - text: "Missing inaction from TiddlerOne", + text: "Missing inaction from [[TiddlerOne]]", filter: "[[one]] [[a a]] [subfilter{hasList!!list}]", tags: [] }, "TiddlerSeventh": { title: "TiddlerSeventh", text: "", - list: "TiddlerOne [[Tiddler Three]] [[a fourth tiddler]] MissingTiddler", + list: "[[TiddlerOne]] [[Tiddler Three]] [[a fourth tiddler]] [[MissingTiddler]]", tags: ["one"] }, "Tiddler8": { @@ -144,7 +144,7 @@ Tests the filtering mechanism. modified: "201304152211" },{ title: "Tiddler Three", - text: "The speed of sound in light\n\nThere is no TiddlerZero but TiddlerSix", + text: "The speed of sound in light\n\nThere is no [[TiddlerZero]] but [[TiddlerSix]]", tags: ["one","two"], cost: "56", value: "80", @@ -252,9 +252,9 @@ Tests the filtering mechanism. }); it("should handle the lookup operator", function() { - expect(wiki.filterTiddlers("Six Seventh 8 +[lookup[Tiddler]]").join(",")).toBe("Missing inaction from TiddlerOne,,Tidd"); - expect(wiki.filterTiddlers("Six Seventh 8 +[lookup:8[Tiddler]]").join(",")).toBe("Missing inaction from TiddlerOne,8,Tidd"); - expect(wiki.filterTiddlers("Six Seventh 8 +[lookup:8[Tiddler],[text]]").join(",")).toBe("Missing inaction from TiddlerOne,8,Tidd"); + expect(wiki.filterTiddlers("Six Seventh 8 +[lookup[Tiddler]]").join(",")).toBe("Missing inaction from [[TiddlerOne]],,Tidd"); + expect(wiki.filterTiddlers("Six Seventh 8 +[lookup:8[Tiddler]]").join(",")).toBe("Missing inaction from [[TiddlerOne]],8,Tidd"); + expect(wiki.filterTiddlers("Six Seventh 8 +[lookup:8[Tiddler],[text]]").join(",")).toBe("Missing inaction from [[TiddlerOne]],8,Tidd"); expect(wiki.filterTiddlers("Six Seventh 8 +[lookup[Tiddler],[tags]]").join(",")).toBe(",one,one"); }); @@ -990,10 +990,10 @@ Tests the filtering mechanism. expect(wiki.filterTiddlers("[!sortsub:number]",anchorWidget).join(",")).toBe("filter regexp test,a fourth tiddler,$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,has filter,TiddlerOne,hasList,one"); expect(wiki.filterTiddlers("[sortsub:string]",anchorWidget).join(",")).toBe("has filter,TiddlerOne,$:/TiddlerTwo,Tiddler Three,$:/ShadowPlugin,a fourth tiddler,filter regexp test,one,hasList"); expect(wiki.filterTiddlers("[!sortsub:string]",anchorWidget).join(",")).toBe("hasList,one,filter regexp test,a fourth tiddler,$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,has filter,TiddlerOne"); - expect(wiki.filterTiddlers("[sortsub:number]",anchorWidget).join(",")).toBe("one,TiddlerOne,hasList,has filter,a fourth tiddler,Tiddler Three,$:/TiddlerTwo,filter regexp test,$:/ShadowPlugin"); - expect(wiki.filterTiddlers("[!sortsub:number]",anchorWidget).join(",")).toBe("$:/ShadowPlugin,filter regexp test,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,has filter,hasList,TiddlerOne,one"); - expect(wiki.filterTiddlers("[sortsub:string]",anchorWidget).join(",")).toBe("one,TiddlerOne,hasList,has filter,$:/ShadowPlugin,a fourth tiddler,Tiddler Three,$:/TiddlerTwo,filter regexp test"); - expect(wiki.filterTiddlers("[!sortsub:string]",anchorWidget).join(",")).toBe("filter regexp test,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,$:/ShadowPlugin,has filter,hasList,TiddlerOne,one"); + expect(wiki.filterTiddlers("[sortsub:number]",anchorWidget).join(",")).toBe("one,TiddlerOne,hasList,has filter,a fourth tiddler,$:/TiddlerTwo,Tiddler Three,filter regexp test,$:/ShadowPlugin"); + expect(wiki.filterTiddlers("[!sortsub:number]",anchorWidget).join(",")).toBe("$:/ShadowPlugin,filter regexp test,Tiddler Three,$:/TiddlerTwo,a fourth tiddler,has filter,hasList,TiddlerOne,one"); + expect(wiki.filterTiddlers("[sortsub:string]",anchorWidget).join(",")).toBe("one,TiddlerOne,hasList,has filter,$:/ShadowPlugin,a fourth tiddler,$:/TiddlerTwo,Tiddler Three,filter regexp test"); + expect(wiki.filterTiddlers("[!sortsub:string]",anchorWidget).join(",")).toBe("filter regexp test,Tiddler Three,$:/TiddlerTwo,a fourth tiddler,$:/ShadowPlugin,has filter,hasList,TiddlerOne,one"); expect(wiki.filterTiddlers("[[TiddlerOne]] [[$:/TiddlerTwo]] [[Tiddler Three]] [[a fourth tiddler]] +[!sortsub:number]",anchorWidget).join(",")).toBe("$:/TiddlerTwo,Tiddler Three,TiddlerOne,a fourth tiddler"); expect(wiki.filterTiddlers("a1 a10 a2 a3 b10 b3 b1 c9 c11 c1 +[sortsub:alphanumeric]",anchorWidget).join(",")).toBe("a1,a2,a3,a10,b1,b3,b10,c1,c9,c11"); // #7155. The order of the output is the same as the input when an undefined variable is used in the subfitler diff --git a/editions/test/tiddlers/tests/test-wikitext.js b/editions/test/tiddlers/tests/test-wikitext.js index cdd729cfc..eddef73f7 100644 --- a/editions/test/tiddlers/tests/test-wikitext.js +++ b/editions/test/tiddlers/tests/test-wikitext.js @@ -45,16 +45,6 @@ describe("WikiText tests", function() { it("should support attributes specified as macro invocations", function() { expect(wiki.renderTiddler("text/html","TiddlerFour")).toBe("

This is a link

"); }); - it("should identify wikiwords to automatically link", function() { - expect(wiki.renderText("text/html","text/vnd-tiddlywiki","No wikilinks here").indexOf("header"); expect(wiki.renderText("text/html","text/vnd-tiddlywiki","@@.myclass\n
\n\nContent
\n@@")).toBe("

Content

"); diff --git a/editions/tw5.com/tiddlers/system/configWikiParserRulesInlineWikilink.tid b/editions/tw5.com/tiddlers/system/configWikiParserRulesInlineWikilink.tid new file mode 100644 index 000000000..9a395abd6 --- /dev/null +++ b/editions/tw5.com/tiddlers/system/configWikiParserRulesInlineWikilink.tid @@ -0,0 +1,3 @@ +title: $:/config/WikiParserRules/Inline/wikilink + +enable \ No newline at end of file From 98e72558d03ba5242d847265525f62dc93d434a5 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Fri, 9 Jun 2023 08:35:42 +0100 Subject: [PATCH 11/94] Default site title no longer needs a tilde Now that CamelCase linking is disabled by default --- core/language/en-GB/SiteTitle.tid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/language/en-GB/SiteTitle.tid b/core/language/en-GB/SiteTitle.tid index 9f522664a..a32da7dfe 100644 --- a/core/language/en-GB/SiteTitle.tid +++ b/core/language/en-GB/SiteTitle.tid @@ -1,3 +1,3 @@ title: $:/SiteTitle -My ~TiddlyWiki \ No newline at end of file +My TiddlyWiki \ No newline at end of file From cc383e6d1e7c3a2dde5ab91dcf5b6fa7aca53121 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Sat, 10 Jun 2023 08:58:04 +0100 Subject: [PATCH 12/94] Refactor function evaluation code to avoid adding evaluateVariable method Adding the new widget method was causing backwards compatibility issues. For example, see this discussion: https://talk.tiddlywiki.org/t/tw-v5-3-0-pre-problem-with-autocomplete-plugin/6958 --- core/modules/filters.js | 3 +- core/modules/filters/function.js | 8 ++- core/modules/filters/unknown.js | 10 ++-- core/modules/widgets/transclude.js | 17 +----- core/modules/widgets/widget.js | 87 ++++++++++-------------------- 5 files changed, 43 insertions(+), 82 deletions(-) diff --git a/core/modules/filters.js b/core/modules/filters.js index b705c994c..d4fd355c6 100644 --- a/core/modules/filters.js +++ b/core/modules/filters.js @@ -269,7 +269,8 @@ exports.compileFilter = function(filterString) { operand.value = self.getTextReference(operand.text,"",currTiddlerTitle); } else if(operand.variable) { var varTree = $tw.utils.parseFilterVariable(operand.text); - operand.value = widget.evaluateVariable(varTree.name,{params: varTree.params, source: source})[0] || ""; + var variableInfo = widget.getVariableInfo(varTree.name,{params: varTree.params, source: source}); + operand.value = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || ""; } else { operand.value = operand.text; } diff --git a/core/modules/filters/function.js b/core/modules/filters/function.js index f6a8c034d..79210fb78 100644 --- a/core/modules/filters/function.js +++ b/core/modules/filters/function.js @@ -17,9 +17,13 @@ Export our filter function */ exports.function = function(source,operator,options) { var functionName = operator.operands[0], - variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName); + params = []; + $tw.utils.each(operator.operands.slice(1),function(param) { + params.push({value: param}); + }); + var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName,{params: params, source: source}); if(variableInfo && variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) { - return options.widget.evaluateVariable(functionName,{params: operator.operands.slice(1), source: source}); + return variableInfo.resultList ? variableInfo.resultList : [variableInfo.text]; } // Return the input list if the function wasn't found var results = []; diff --git a/core/modules/filters/unknown.js b/core/modules/filters/unknown.js index 1cc5d16e2..6ae5baaf0 100644 --- a/core/modules/filters/unknown.js +++ b/core/modules/filters/unknown.js @@ -22,9 +22,13 @@ Export our filter function exports["[unknown]"] = function(source,operator,options) { // Check for a user defined filter operator if(operator.operator.indexOf(".") !== -1) { - var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator); - if(variableInfo && variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) { - var list = options.widget.evaluateVariable(operator.operator,{params: operator.operands, source: source}); + var params = []; + $tw.utils.each(operator.operands,function(param) { + params.push({value: param}); + }); + var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator,{params: params, source: source}); + if(variableInfo && variableInfo.srcVariable) { + var list = variableInfo.resultList ? variableInfo.resultList : [variableInfo.text]; if(operator.prefix === "!") { var results = []; source(function(tiddler,title) { diff --git a/core/modules/widgets/transclude.js b/core/modules/widgets/transclude.js index f50e32c64..1117598de 100755 --- a/core/modules/widgets/transclude.js +++ b/core/modules/widgets/transclude.js @@ -179,22 +179,7 @@ TranscludeWidget.prototype.getTransclusionTarget = function() { if(variableInfo.text) { if(srcVariable.isFunctionDefinition) { // Function to return parameters by name or position - var fnGetParam = function(name,index) { - // Parameter names starting with dollar must be escaped to double dollars - if(name.charAt(0) === "$") { - name = "$" + name; - } - // Look for the parameter by name - if(self.hasAttribute(name)) { - return self.getAttribute(name); - // Look for the parameter by index - } else if(self.hasAttribute(index + "")) { - return self.getAttribute(index + ""); - } else { - return undefined; - } - }, - result = this.evaluateVariable(this.transcludeVariable,{params: fnGetParam})[0] || ""; + var result = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || ""; parser = { tree: [{ type: "text", diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index 6f9a8e4e1..8d9c05950 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -112,14 +112,18 @@ Get the prevailing value of a context variable name: name of variable options: see below Options include + params: array of {name:, value:} for each parameter defaultValue: default value if the variable is not defined +source: optional source iterator for evaluating function invocations allowSelfAssigned: if true, includes the current widget in the context chain instead of just the parent Returns an object with the following fields: -params: array of {name:,value:} of parameters passed to wikitext variables +params: array of {name:,value:} or {value:} of parameters to be applied text: text of variable, with parameters properly substituted +resultList: result of variable evaluation as an array +srcVariable: reference to the object defining the variable */ Widget.prototype.getVariableInfo = function(name,options) { options = options || {}; @@ -135,7 +139,8 @@ Widget.prototype.getVariableInfo = function(name,options) { if(variable) { var originalValue = variable.value, value = originalValue, - params = []; + params = [], + resultList = [value]; // Only substitute parameter and variable references if this variable was defined with the \define pragma if(variable.isMacroDefinition) { params = self.resolveVariableParameters(variable.params,actualParams); @@ -144,10 +149,28 @@ Widget.prototype.getVariableInfo = function(name,options) { value = $tw.utils.replaceString(value,new RegExp("\\$" + $tw.utils.escapeRegExp(param.name) + "\\$","mg"),param.value); }); value = self.substituteVariableReferences(value,options); + resultList = [value]; + } else if(variable.isFunctionDefinition) { + // Function evaluations + params = self.resolveVariableParameters(variable.params,actualParams); + var variables = Object.create(null); + // Apply default parameter values + $tw.utils.each(variable.params,function(param,index) { + if(param["default"]) { + variables[param.name] = param["default"]; + } + }); + // Parameters are an array of {value:} or {name:, value:} pairs + $tw.utils.each(params,function(param) { + variables[param.name] = param.value; + }); + resultList = this.wiki.filterTiddlers(value,this.makeFakeWidgetWithVariables(variables),options.source); + value = resultList[0] || ""; } return { text: value, params: params, + resultList: resultList, srcVariable: variable, isCacheable: originalValue === value }; @@ -159,6 +182,7 @@ Widget.prototype.getVariableInfo = function(name,options) { } return { text: text, + resultList: [text], srcVariable: {} }; }; @@ -317,62 +341,11 @@ Widget.prototype.makeFakeWidgetWithVariables = function(variables) { }; }, makeFakeWidgetWithVariables: self.makeFakeWidgetWithVariables, - evaluateVariable: self.evaluateVariable, resolveVariableParameters: self.resolveVariableParameters, wiki: self.wiki }; }; -/* -Evaluate a variable and associated actual parameters and return the resulting array. -The way that the variable is evaluated depends upon its type: -* Functions are evaluated as parameterised filter strings -* Macros are returned as plain text with substitution of parameters -* Procedures and widgets are returned as plain text - -Options are: -params - the actual parameters – may be one of: - * an array of values that may be an anonymous string value, or a {name:, value:} pair - * a hashmap of {name: value} pairs - * a function invoked with parameters (name,index) that returns a parameter value by name or position -source - iterator for source tiddlers -*/ -Widget.prototype.evaluateVariable = function(name,options) { - options = options || {}; - var params = options.params || []; - // Get the details of the variable (includes processing text substitution for macros - var variableInfo = this.getVariableInfo(name,{params: params,defaultValue: ""}); - // Process function parameters - var variables = Object.create(null); - if(variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) { - // Apply default parameter values - $tw.utils.each(variableInfo.srcVariable.params,function(param,index) { - if(param["default"]) { - variables[param.name] = param["default"]; - } - }); - if($tw.utils.isArray(params)) { - // Parameters are an array of values or {name:, value:} pairs - $tw.utils.each(this.resolveVariableParameters(variableInfo.srcVariable.params,params),function(param) { - variables[param.name] = param.value; - }); - } else if(typeof params === "function") { - // Parameters are passed via a function - $tw.utils.each(variableInfo.srcVariable.params,function(param,index) { - variables[param.name] = params(param.name,index) || param["default"] || ""; - }); - } else { - // Parameters are a hashmap - $tw.utils.each(params,function(value,name) { - variables[name] = value; - }); - } - return this.wiki.filterTiddlers(variableInfo.text,this.makeFakeWidgetWithVariables(variables),options.source); - } else { - return [variableInfo.text]; - } -}; - /* Compute the current values of the attributes of the widget. Returns a hashmap of the names of the attributes that have changed. Options include: @@ -406,13 +379,7 @@ Widget.prototype.computeAttribute = function(attribute) { value = this.wiki.getTextReference(attribute.textReference,"",this.getVariable("currentTiddler")) || ""; } else if(attribute.type === "macro") { var variableInfo = this.getVariableInfo(attribute.value.name,{params: attribute.value.params}); - if(variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) { - // It is a function definition. Go through each of the defined parameters, and make a variable with the value of the corresponding provided parameter - var paramArray = this.resolveVariableParameters(variableInfo.srcVariable.params,attribute.value.params); - value = this.evaluateVariable(attribute.value.name,{params: paramArray})[0] || ""; - } else { - value = variableInfo.text; - } + value = variableInfo.text; } else { // String attribute value = attribute.value; } From 66212cd4917917fc646d255d3f1b43232755700a Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Sun, 11 Jun 2023 09:46:05 +0100 Subject: [PATCH 13/94] Refactor dependency on widget.getVariableInfo Fixing https://talk.tiddlywiki.org/t/tw-v5-3-0-pre-problem-with-autocomplete-plugin/6958/9?u=jeremyruston --- core/modules/filters.js | 5 +++-- core/modules/widgets/widget.js | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/core/modules/filters.js b/core/modules/filters.js index d4fd355c6..aa82a352a 100644 --- a/core/modules/filters.js +++ b/core/modules/filters.js @@ -12,6 +12,8 @@ Adds tiddler filtering methods to the $tw.Wiki object. /*global $tw: false */ "use strict"; +var widgetClass = require("$:/core/modules/widgets/widget.js").widget; + /* Maximum permitted filter recursion depth */ var MAX_FILTER_DEPTH = 300; @@ -269,8 +271,7 @@ exports.compileFilter = function(filterString) { operand.value = self.getTextReference(operand.text,"",currTiddlerTitle); } else if(operand.variable) { var varTree = $tw.utils.parseFilterVariable(operand.text); - var variableInfo = widget.getVariableInfo(varTree.name,{params: varTree.params, source: source}); - operand.value = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || ""; + operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || ""; } else { operand.value = operand.text; } diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index 8d9c05950..c0d2bc7a6 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -796,6 +796,20 @@ Widget.prototype.allowActionPropagation = function() { return true; }; +/* +Evaluate a variable with parameters. This is a static convenience method that attempts to evaluate a variable as a function, returning an array of strings +*/ +Widget.evaluateVariable = function(widget,name,options) { + var result; + if(widget.getVariableInfo) { + var variableInfo = widget.getVariableInfo(name,options); + result = variableInfo.resultList || [variableInfo.text]; + } else { + result = [widget.getVariable(name)]; + } + return result; +}; + exports.widget = Widget; })(); From 578e883bdcc48979acd8800dae5622e5cf33ad17 Mon Sep 17 00:00:00 2001 From: GameDungeon <60719255+GameDungeon@users.noreply.github.com> Date: Sun, 11 Jun 2023 04:28:52 -0500 Subject: [PATCH 14/94] Add Tabs To Settings (#7524) * Move to Core * List-Before * Update core/ui/ControlPanel/Settings.tid * Proper list-before --- core/ui/ControlPanel/Settings.tid | 18 +++--------------- .../ui/ControlPanel/TiddlyWiki.tid | 1 + .../codemirror/ui/controlpanel/settings.tid | 7 ------- 3 files changed, 4 insertions(+), 22 deletions(-) rename plugins/tiddlywiki/codemirror/ui/controlpanel/tiddlywiki.tid => core/ui/ControlPanel/TiddlyWiki.tid (96%) delete mode 100644 plugins/tiddlywiki/codemirror/ui/controlpanel/settings.tid diff --git a/core/ui/ControlPanel/Settings.tid b/core/ui/ControlPanel/Settings.tid index f4a4b13c2..74004ffa0 100644 --- a/core/ui/ControlPanel/Settings.tid +++ b/core/ui/ControlPanel/Settings.tid @@ -2,18 +2,6 @@ title: $:/core/ui/ControlPanel/Settings tags: $:/tags/ControlPanel caption: {{$:/language/ControlPanel/Settings/Caption}} -\define lingo-base() $:/language/ControlPanel/Settings/ - -<> - -<$list filter="[all[shadows+tiddlers]tag[$:/tags/ControlPanel/Settings]]"> - -
- -!! <$link><$transclude field="caption"/> - -<$transclude/> - -
- - +
+<$macrocall $name="tabs" tabsList="[all[shadows+tiddlers]tag[$:/tags/ControlPanel/SettingsTab]!has[draft.of]]" default="$:/core/ui/ControlPanel/Settings/TiddlyWiki" explicitState="$:/state/tab--697582678"/> +
\ No newline at end of file diff --git a/plugins/tiddlywiki/codemirror/ui/controlpanel/tiddlywiki.tid b/core/ui/ControlPanel/TiddlyWiki.tid similarity index 96% rename from plugins/tiddlywiki/codemirror/ui/controlpanel/tiddlywiki.tid rename to core/ui/ControlPanel/TiddlyWiki.tid index f88865997..40be32139 100644 --- a/plugins/tiddlywiki/codemirror/ui/controlpanel/tiddlywiki.tid +++ b/core/ui/ControlPanel/TiddlyWiki.tid @@ -1,6 +1,7 @@ title: $:/core/ui/ControlPanel/Settings/TiddlyWiki tags: $:/tags/ControlPanel/SettingsTab caption: TiddlyWiki +list-before: \define lingo-base() $:/language/ControlPanel/Settings/ diff --git a/plugins/tiddlywiki/codemirror/ui/controlpanel/settings.tid b/plugins/tiddlywiki/codemirror/ui/controlpanel/settings.tid deleted file mode 100644 index 1efe8b867..000000000 --- a/plugins/tiddlywiki/codemirror/ui/controlpanel/settings.tid +++ /dev/null @@ -1,7 +0,0 @@ -title: $:/core/ui/ControlPanel/Settings -tags: $:/tags/ControlPanel -caption: {{$:/language/ControlPanel/Settings/Caption}} - -
-<$macrocall $name="tabs" tabsList="[all[shadows+tiddlers]tag[$:/tags/ControlPanel/SettingsTab]!has[draft.of]]" default="$:/core/ui/ControlPanel/Settings/TiddlyWiki" explicitState="$:/state/tab--697582678"/> -
From 6efd6dbf8b631a1afccc8945bd08630e2a5f3b23 Mon Sep 17 00:00:00 2001 From: Carlo Colombo Date: Sun, 11 Jun 2023 11:36:02 +0200 Subject: [PATCH 15/94] Update Jasmine website (#7533) pivotal.github.io/jasmine website does not exists anymore, replaced with the current Jasmine website --- core/acknowledgements.tid | 2 +- .../dev/tiddlers/from tw5.com/mechanisms/TestingMechanism.tid | 2 +- editions/es-ES/tiddlers/$__Acknowledgements.tid | 2 +- editions/fr-FR/tiddlers/$__Acknowledgements.tid | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/acknowledgements.tid b/core/acknowledgements.tid index e7acee129..cb54e3d23 100644 --- a/core/acknowledgements.tid +++ b/core/acknowledgements.tid @@ -3,7 +3,7 @@ title: $:/Acknowledgements TiddlyWiki incorporates code from these fine OpenSource projects: * [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]] -* [[The Jasmine JavaScript Test Framework|http://pivotal.github.io/jasmine/]] +* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]] * [[Normalize.css by Nicolas Gallagher|http://necolas.github.io/normalize.css/]] And media from these projects: diff --git a/editions/dev/tiddlers/from tw5.com/mechanisms/TestingMechanism.tid b/editions/dev/tiddlers/from tw5.com/mechanisms/TestingMechanism.tid index c334ab256..37659629f 100644 --- a/editions/dev/tiddlers/from tw5.com/mechanisms/TestingMechanism.tid +++ b/editions/dev/tiddlers/from tw5.com/mechanisms/TestingMechanism.tid @@ -2,7 +2,7 @@ modified: 20141013085608911 tags: Mechanisms title: TestingMechanism -TiddlyWiki5 incorporates the Jasmine JavaScript testing framework (see http://pivotal.github.io/jasmine/). It allows the same tests to be run both in the browser and under Node.js. +TiddlyWiki5 incorporates the Jasmine JavaScript testing framework (see https://jasmine.github.io/). It allows the same tests to be run both in the browser and under Node.js. ! TiddlyWiki5 Testing Components diff --git a/editions/es-ES/tiddlers/$__Acknowledgements.tid b/editions/es-ES/tiddlers/$__Acknowledgements.tid index 48074d928..d907bc9e6 100644 --- a/editions/es-ES/tiddlers/$__Acknowledgements.tid +++ b/editions/es-ES/tiddlers/$__Acknowledgements.tid @@ -6,7 +6,7 @@ type: text/vnd.tiddlywiki TiddlyWiki incorpora código de los siguientes proyectos OpenSource: * [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]] -* [[The Jasmine JavaScript Test Framework|http://pivotal.github.io/jasmine/]] +* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]] * [[Normalize.css by Nicolas Gallagher|http://necolas.github.io/normalize.css/]] ...y materiales de estos otros proyectos: diff --git a/editions/fr-FR/tiddlers/$__Acknowledgements.tid b/editions/fr-FR/tiddlers/$__Acknowledgements.tid index 1adf217a0..6e9f6e0e5 100644 --- a/editions/fr-FR/tiddlers/$__Acknowledgements.tid +++ b/editions/fr-FR/tiddlers/$__Acknowledgements.tid @@ -6,7 +6,7 @@ type: text/vnd.tiddlywiki TiddlyWiki intègre du code provenant de ces excellents projets OpenSource<> * [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]] -* [[The Jasmine JavaScript Test Framework|http://pivotal.github.io/jasmine/]] +* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]] * [[Normalize.css by Nicolas Gallagher|http://necolas.github.io/normalize.css/]] Et des contenus provenenant de ces sources<> From a12a9bd93941748e20c5748170ed22cf5fb7cff0 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Mon, 12 Jun 2023 09:22:20 +0100 Subject: [PATCH 16/94] Fixes to browser storage plugin icon --- plugins/tiddlywiki/browser-storage/icon.tid | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/tiddlywiki/browser-storage/icon.tid b/plugins/tiddlywiki/browser-storage/icon.tid index bf3011bf4..4442ed32e 100644 --- a/plugins/tiddlywiki/browser-storage/icon.tid +++ b/plugins/tiddlywiki/browser-storage/icon.tid @@ -1,12 +1,12 @@ title: $:/plugins/tiddlywiki/browser-storage/icon tags: $:/tags/Image - + - - - - - + + + + + \ No newline at end of file From d1f90f075f7cf41531f5e967b02acbc244885904 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Tue, 13 Jun 2023 10:35:55 +0100 Subject: [PATCH 17/94] Add tm-http-request message for making HTTP requests (#7422) * Initial Commit * HttpClient object shouldn't need to know about events * Add support for cancelling HTTP requests * Make the number of outstanding HTTP requests available in a state tiddler * Add a network activity button Click it to cancel outstanding requests * Fix typo Thanks @btheado Co-authored-by: btheado * Fix crash when cancelling more than one HTTP request Thanks @saqimtiaz * Further fixes to cancelling outstanding HTTP requests * Fix missing body --------- Co-authored-by: btheado --- core/images/network-activity.tid | 11 + core/language/en-GB/Buttons.multids | 2 + core/modules/startup/rootwidget.js | 32 +++ core/modules/utils/dom/http.js | 221 +++++++++++++++++- core/modules/wiki.js | 8 + core/palettes/Vanilla.tid | 1 + core/ui/PageControls/network-activity.tid | 16 ++ core/wiki/config/PageControlButtons.multids | 1 + core/wiki/tags/PageControls.tid | 2 +- ...etMessage_ tm-http-cancel-all-requests.tid | 12 + ...essage_ tm-http-request Example Zotero.tid | 115 +++++++++ .../WidgetMessage_ tm-http-request.tid | 51 ++++ .../tiddlers/messages/config-zotero-group.tid | 2 + themes/tiddlywiki/vanilla/base.tid | 4 + 14 files changed, 475 insertions(+), 3 deletions(-) create mode 100644 core/images/network-activity.tid create mode 100644 core/ui/PageControls/network-activity.tid create mode 100644 editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-cancel-all-requests.tid create mode 100644 editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Zotero.tid create mode 100644 editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request.tid create mode 100644 editions/tw5.com/tiddlers/messages/config-zotero-group.tid diff --git a/core/images/network-activity.tid b/core/images/network-activity.tid new file mode 100644 index 000000000..2efdfd4d4 --- /dev/null +++ b/core/images/network-activity.tid @@ -0,0 +1,11 @@ +title: $:/core/images/network-activity +tags: $:/tags/Image + + +<$list filter="[{$:/state/http-requests}match[0]]" variable="ignore"> + + +<$list filter="[{$:/state/http-requests}!match[0]]" variable="ignore"> + + + \ No newline at end of file diff --git a/core/language/en-GB/Buttons.multids b/core/language/en-GB/Buttons.multids index 85a71ac08..fa769d117 100644 --- a/core/language/en-GB/Buttons.multids +++ b/core/language/en-GB/Buttons.multids @@ -67,6 +67,8 @@ More/Caption: more More/Hint: More actions NewHere/Caption: new here NewHere/Hint: Create a new tiddler tagged with this one +NetworkActivity/Caption: network activity +NetworkActivity/Hint: Cancel all network activity NewJournal/Caption: new journal NewJournal/Hint: Create a new journal tiddler NewJournalHere/Caption: new journal here diff --git a/core/modules/startup/rootwidget.js b/core/modules/startup/rootwidget.js index 1175f6f25..f5d90afb5 100644 --- a/core/modules/startup/rootwidget.js +++ b/core/modules/startup/rootwidget.js @@ -20,6 +20,38 @@ exports.before = ["story"]; exports.synchronous = true; exports.startup = function() { + // Install the HTTP client event handler + $tw.httpClient = new $tw.utils.HttpClient(); + var getPropertiesWithPrefix = function(properties,prefix) { + var result = Object.create(null); + $tw.utils.each(properties,function(value,name) { + if(name.indexOf(prefix) === 0) { + result[name.substring(prefix.length)] = properties[name]; + } + }); + return result; + }; + $tw.rootWidget.addEventListener("tm-http-request",function(event) { + var params = event.paramObject || {}; + $tw.httpClient.initiateHttpRequest({ + wiki: event.widget.wiki, + url: params.url, + method: params.method, + body: params.body, + oncompletion: params.oncompletion, + onprogress: params.onprogress, + bindStatus: params["bind-status"], + bindProgress: params["bind-progress"], + variables: getPropertiesWithPrefix(params,"var-"), + headers: getPropertiesWithPrefix(params,"header-"), + passwordHeaders: getPropertiesWithPrefix(params,"password-header-"), + queryStrings: getPropertiesWithPrefix(params,"query-"), + passwordQueryStrings: getPropertiesWithPrefix(params,"password-query-") + }); + }); + $tw.rootWidget.addEventListener("tm-http-cancel-all-requests",function(event) { + $tw.httpClient.cancelAllHttpRequests(); + }); // Install the modal message mechanism $tw.modal = new $tw.utils.Modal($tw.wiki); $tw.rootWidget.addEventListener("tm-modal",function(event) { diff --git a/core/modules/utils/dom/http.js b/core/modules/utils/dom/http.js index 6e07b1040..ba4b3d2a1 100644 --- a/core/modules/utils/dom/http.js +++ b/core/modules/utils/dom/http.js @@ -3,7 +3,7 @@ title: $:/core/modules/utils/dom/http.js type: application/javascript module-type: utils -Browser HTTP support +HTTP support \*/ (function(){ @@ -13,11 +13,204 @@ Browser HTTP support "use strict"; /* -A quick and dirty HTTP function; to be refactored later. Options are: +Manage tm-http-request events. Options include: +wiki: Reference to the wiki to be used for state tiddler tracking +stateTrackerTitle: Title of tiddler to be used for state tiddler tracking +*/ +function HttpClient(options) { + options = options || {}; + this.nextId = 1; + this.wiki = options.wiki || $tw.wiki; + this.stateTrackerTitle = options.stateTrackerTitle || "$:/state/http-requests"; + this.requests = []; // Array of {id: string,request: HttpClientRequest} + this.updateRequestTracker(); +} + +/* +Return the index into this.requests[] corresponding to a given ID. Returns null if not found +*/ +HttpClient.prototype.getRequestIndex = function(targetId) { + var targetIndex = null; + $tw.utils.each(this.requests,function(requestInfo,index) { + if(requestInfo.id === targetId) { + targetIndex = index; + } + }); + return targetIndex; +}; + +/* +Update the state tiddler that is tracking the outstanding requests +*/ +HttpClient.prototype.updateRequestTracker = function() { + this.wiki.addTiddler({title: this.stateTrackerTitle, text: "" + this.requests.length}); +}; + +HttpClient.prototype.initiateHttpRequest = function(options) { + var self = this, + id = this.nextId, + request = new HttpClientRequest(options); + this.nextId += 1; + this.requests.push({id: id, request: request}); + this.updateRequestTracker(); + request.send(function(err) { + var targetIndex = self.getRequestIndex(id); + if(targetIndex !== null) { + self.requests.splice(targetIndex,1); + self.updateRequestTracker(); + } + }); + return id; +}; + +HttpClient.prototype.cancelAllHttpRequests = function() { + var self = this; + if(this.requests.length > 0) { + for(var t=this.requests.length - 1; t--; t>=0) { + var requestInfo = this.requests[t]; + requestInfo.request.cancel(); + } + } + this.requests = []; + this.updateRequestTracker(); +}; + +HttpClient.prototype.cancelHttpRequest = function(targetId) { + var targetIndex = this.getRequestIndex(targetId); + if(targetIndex !== null) { + this.requests[targetIndex].request.cancel(); + this.requests.splice(targetIndex,1); + this.updateRequestTracker(); + } +}; + +/* +Initiate an HTTP request. Options: +wiki: wiki to be used for executing action strings +url: URL for request +method: method eg GET, POST +body: text of request body +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 +bindProgress: optional title of tiddler to which the progress of the request (0 to 100) should be bound +variables: hashmap of variable name to string value passed to action strings +headers: hashmap of header name to header value to be sent with the request +passwordHeaders: hashmap of header name to password store name to be sent with the request +queryStrings: hashmap of query string parameter name to parameter value to be sent with the request +passwordQueryStrings: hashmap of query string parameter name to password store name to be sent with the request +*/ +function HttpClientRequest(options) { + var self = this; + console.log("Initiating an HTTP request",options) + this.wiki = options.wiki; + this.completionActions = options.oncompletion; + this.progressActions = options.onprogress; + this.bindStatus = options["bind-status"]; + this.bindProgress = options["bind-progress"]; + this.method = options.method || "GET"; + this.body = options.body || ""; + this.variables = options.variables; + var url = options.url; + $tw.utils.each(options.queryStrings,function(value,name) { + url = $tw.utils.setQueryStringParameter(url,name,value); + }); + $tw.utils.each(options.passwordQueryStrings,function(value,name) { + url = $tw.utils.setQueryStringParameter(url,name,$tw.utils.getPassword(value) || ""); + }); + this.url = url; + this.requestHeaders = {}; + $tw.utils.each(options.headers,function(value,name) { + self.requestHeaders[name] = value; + }); + $tw.utils.each(options.passwordHeaders,function(value,name) { + self.requestHeaders[name] = $tw.utils.getPassword(value) || ""; + }); +} + +HttpClientRequest.prototype.send = function(callback) { + var self = this, + setBinding = function(title,text) { + if(title) { + this.wiki.addTiddler(new $tw.Tiddler({title: title, text: text})); + } + }; + if(this.url) { + setBinding(this.bindStatus,"pending"); + setBinding(this.bindProgress,"0"); + // Set the request tracker tiddler + var requestTrackerTitle = this.wiki.generateNewTitle("$:/temp/HttpRequest"); + this.wiki.addTiddler({ + title: requestTrackerTitle, + tags: "$:/tags/HttpRequest", + text: JSON.stringify({ + url: this.url, + type: this.method, + status: "inprogress", + headers: this.requestHeaders, + data: this.body + }) + }); + this.xhr = $tw.utils.httpRequest({ + url: this.url, + type: this.method, + headers: this.requestHeaders, + data: this.body, + callback: function(err,data,xhr) { + var hasSucceeded = xhr.status >= 200 && xhr.status < 300, + completionCode = hasSucceeded ? "complete" : "error", + headers = {}; + $tw.utils.each(xhr.getAllResponseHeaders().split("\r\n"),function(line) { + var pos = line.indexOf(":"); + if(pos !== -1) { + headers[line.substr(0,pos)] = line.substr(pos + 1).trim(); + } + }); + setBinding(self.bindStatus,completionCode); + setBinding(self.bindProgress,"100"); + var resultVariables = { + status: xhr.status.toString(), + statusText: xhr.statusText, + error: (err || "").toString(), + data: (data || "").toString(), + headers: JSON.stringify(headers) + }; + self.wiki.addTiddler(new $tw.Tiddler(self.wiki.getTiddler(requestTrackerTitle),{ + status: completionCode, + })); + self.wiki.invokeActionString(self.completionActions,undefined,$tw.utils.extend({},self.variables,resultVariables),{parentWidget: $tw.rootWidget}); + callback(hasSucceeded ? null : xhr.statusText); + // console.log("Back!",err,data,xhr); + }, + progress: function(lengthComputable,loaded,total) { + if(lengthComputable) { + setBinding(self.bindProgress,"" + Math.floor((loaded/total) * 100)) + } + self.wiki.invokeActionString(self.progressActions,undefined,{ + lengthComputable: lengthComputable ? "yes" : "no", + loaded: loaded, + total: total + },{parentWidget: $tw.rootWidget}); + } + }); + } +}; + +HttpClientRequest.prototype.cancel = function() { + if(this.xhr) { + this.xhr.abort(); + } +}; + +exports.HttpClient = HttpClient; + +/* +Make an HTTP request. Options are: url: URL to retrieve headers: hashmap of headers to send type: GET, PUT, POST etc callback: function invoked with (err,data,xhr) + progress: optional function invoked with (lengthComputable,loaded,total) returnProp: string name of the property to return as first argument of callback */ exports.httpRequest = function(options) { @@ -83,8 +276,16 @@ exports.httpRequest = function(options) { options.callback($tw.language.getString("Error/XMLHttpRequest") + ": " + this.status,null,this); } }; + // Handle progress + if(options.progress) { + request.onprogress = function(event) { + console.log("Progress event",event) + options.progress(event.lengthComputable,event.loaded,event.total); + }; + } // Make the request request.open(type,url,true); + // Headers if(headers) { $tw.utils.each(headers,function(header,headerTitle,object) { request.setRequestHeader(headerTitle,header); @@ -96,6 +297,7 @@ exports.httpRequest = function(options) { if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers)) { request.setRequestHeader("X-Requested-With","TiddlyWiki"); } + // Send data try { request.send(data); } catch(e) { @@ -104,4 +306,19 @@ exports.httpRequest = function(options) { return request; }; +exports.setQueryStringParameter = function(url,paramName,paramValue) { + var URL = $tw.browser ? window.URL : require("url").URL, + newUrl; + try { + newUrl = new URL(url); + } catch(e) { + } + if(newUrl && paramName) { + newUrl.searchParams.set(paramName,paramValue || ""); + return newUrl.toString(); + } else { + return url; + } +}; + })(); diff --git a/core/modules/wiki.js b/core/modules/wiki.js index 8cb12cc39..ca31da8d2 100755 --- a/core/modules/wiki.js +++ b/core/modules/wiki.js @@ -1415,6 +1415,14 @@ exports.checkTiddlerText = function(title,targetText,options) { return text === targetText; } +/* +Execute an action string without an associated context widget +*/ +exports.invokeActionString = function(actions,event,variables,options) { + var widget = this.makeWidget(null,{parentWidget: options.parentWidget}); + widget.invokeActionString(actions,null,event,variables); +}; + /* Read an array of browser File objects, invoking callback(tiddlerFieldsArray) once they're all read */ diff --git a/core/palettes/Vanilla.tid b/core/palettes/Vanilla.tid index d84b4ec83..4c660e912 100644 --- a/core/palettes/Vanilla.tid +++ b/core/palettes/Vanilla.tid @@ -54,6 +54,7 @@ modal-footer-background: #f5f5f5 modal-footer-border: #dddddd modal-header-border: #eeeeee muted-foreground: #bbb +network-activity-foreground: #448844 notification-background: #ffffdd notification-border: #999999 page-background: #f4f4f4 diff --git a/core/ui/PageControls/network-activity.tid b/core/ui/PageControls/network-activity.tid new file mode 100644 index 000000000..763365f37 --- /dev/null +++ b/core/ui/PageControls/network-activity.tid @@ -0,0 +1,16 @@ +title: $:/core/ui/Buttons/network-activity +tags: $:/tags/PageControls +caption: {{$:/core/images/network-activity}} {{$:/language/Buttons/NetworkActivity/Caption}} +description: {{$:/language/Buttons/NetworkActivity/Hint}} + +\whitespace trim +<$button message="tm-http-cancel-all-requests" tooltip={{$:/language/Buttons/NetworkActivity/Hint}} aria-label={{$:/language/Buttons/NetworkActivity/Caption}} class=<>> +<$list filter="[match[yes]]"> +{{$:/core/images/network-activity}} + +<$list filter="[match[yes]]"> + +<$text text={{$:/language/Buttons/NetworkActivity/Caption}}/> + + + \ No newline at end of file diff --git a/core/wiki/config/PageControlButtons.multids b/core/wiki/config/PageControlButtons.multids index a437251f5..b66f11cc0 100644 --- a/core/wiki/config/PageControlButtons.multids +++ b/core/wiki/config/PageControlButtons.multids @@ -13,6 +13,7 @@ core/ui/Buttons/language: hide core/ui/Buttons/tag-manager: hide core/ui/Buttons/manager: hide core/ui/Buttons/more-page-actions: hide +core/ui/Buttons/network-activity: hide core/ui/Buttons/new-journal: hide core/ui/Buttons/new-image: hide core/ui/Buttons/palette: hide diff --git a/core/wiki/tags/PageControls.tid b/core/wiki/tags/PageControls.tid index c6234751c..c0f1cb233 100644 --- a/core/wiki/tags/PageControls.tid +++ b/core/wiki/tags/PageControls.tid @@ -1,2 +1,2 @@ title: $:/tags/PageControls -list: [[$:/core/ui/Buttons/home]] [[$:/core/ui/Buttons/close-all]] [[$:/core/ui/Buttons/fold-all]] [[$:/core/ui/Buttons/unfold-all]] [[$:/core/ui/Buttons/permaview]] [[$:/core/ui/Buttons/new-tiddler]] [[$:/core/ui/Buttons/new-journal]] [[$:/core/ui/Buttons/new-image]] [[$:/core/ui/Buttons/import]] [[$:/core/ui/Buttons/export-page]] [[$:/core/ui/Buttons/control-panel]] [[$:/core/ui/Buttons/advanced-search]] [[$:/core/ui/Buttons/manager]] [[$:/core/ui/Buttons/tag-manager]] [[$:/core/ui/Buttons/language]] [[$:/core/ui/Buttons/palette]] [[$:/core/ui/Buttons/theme]] [[$:/core/ui/Buttons/layout]] [[$:/core/ui/Buttons/storyview]] [[$:/core/ui/Buttons/encryption]] [[$:/core/ui/Buttons/timestamp]] [[$:/core/ui/Buttons/full-screen]] [[$:/core/ui/Buttons/print]] [[$:/core/ui/Buttons/save-wiki]] [[$:/core/ui/Buttons/refresh]] [[$:/core/ui/Buttons/more-page-actions]] +list: [[$:/core/ui/Buttons/home]] [[$:/core/ui/Buttons/close-all]] [[$:/core/ui/Buttons/fold-all]] [[$:/core/ui/Buttons/unfold-all]] [[$:/core/ui/Buttons/permaview]] [[$:/core/ui/Buttons/new-tiddler]] [[$:/core/ui/Buttons/new-journal]] [[$:/core/ui/Buttons/new-image]] [[$:/core/ui/Buttons/import]] [[$:/core/ui/Buttons/export-page]] [[$:/core/ui/Buttons/control-panel]] [[$:/core/ui/Buttons/advanced-search]] [[$:/core/ui/Buttons/manager]] [[$:/core/ui/Buttons/tag-manager]] [[$:/core/ui/Buttons/language]] [[$:/core/ui/Buttons/palette]] [[$:/core/ui/Buttons/theme]] [[$:/core/ui/Buttons/layout]] [[$:/core/ui/Buttons/storyview]] [[$:/core/ui/Buttons/encryption]] [[$:/core/ui/Buttons/timestamp]] [[$:/core/ui/Buttons/full-screen]] [[$:/core/ui/Buttons/print]] [[$:/core/ui/Buttons/save-wiki]] [[$:/core/ui/Buttons/refresh]] [[$:/core/ui/Buttons/network-activity]] [[$:/core/ui/Buttons/more-page-actions]] diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-cancel-all-requests.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-cancel-all-requests.tid new file mode 100644 index 000000000..df94e5a0b --- /dev/null +++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-cancel-all-requests.tid @@ -0,0 +1,12 @@ +caption: tm-http-cancel-all-requests +created: 20230429161453032 +modified: 20230429161453032 +tags: Messages +title: WidgetMessage: tm-http-cancel-all-requests +type: text/vnd.tiddlywiki + +The ''tm-http-cancel-all-requests'' message is used to cancel all outstanding HTTP requests initiated with [[WidgetMessage: tm-http-request]]. + +Note that the state tiddler $:/state/http-requests contains a number representing the number of outstanding HTTP requests in progress. + +It does not take any parameters. 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 new file mode 100644 index 000000000..ea64dd3a2 --- /dev/null +++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request Example Zotero.tid @@ -0,0 +1,115 @@ +title: WidgetMessage: tm-http-request Example - Zotero +tags: $:/tags/Macro + +\procedure select-zotero-group() +Specify the Zotero group ID to import +<$edit-text tiddler="$:/config/zotero-group" tag="input"/> or +<$select tiddler="$:/config/zotero-group"> + + + + +\end + +\procedure zotero-save-item(item) +<$action-createtiddler + $basetitle={{{ =[[_zotero_import ]] =[jsonget[key]] =[[ ]] =[jsonget[title]] +[join[]] }}} + text={{{ [jsonget[title]] }}} + tags="$:/tags/ZoteroImport" +> + <$action-setmultiplefields $tiddler=<> $fields="[jsonindexes[]addprefix[zotero-]]" $values="[jsonindexes[]] :map[jsongetelse[.XXXXX.]]"/> + <$list filter="[jsonindexes[creators]]" variable="creatorIndex"> + <$action-setmultiplefields $tiddler=<> $fields="[jsonget[creators],,[creatorType]addprefix[zotero-]]" $values="[jsonget[creators],,[lastName]] [jsonget[creators],,[firstName]] +[join[, ]] :else[jsonget[creators],,[name]] "/> + + +\end zotero-save-item + +\procedure zotero-save-items(data) +<$list filter="[jsonindexes[]] :map[jsonextract,[data]]" variable="item"> + <$macrocall $name="zotero-save-item" item=<>/> + +\end zotero-save-items + +\procedure zotero-get-items(start:"0",limit:"25") + +\procedure completion() +\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]] + <$action-log msg="In completion"/> + <$action-log/> + + <$list filter="[compare:number:gteq[200]compare:number:lteq[299]]" variable="ignore"> + + <$macrocall $name="zotero-save-items" data=<>/> + + <$list filter="[jsonget[total-results]subtractsubtractcompare:number:gt[0]]" variable="ignore"> + <$macrocall $name="zotero-get-items" start={{{ [add] }}} limit=<>/> + + +\end completion + +\procedure progress() +\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]] + <$action-log message="In progress-actions"/> +\end progress + +\procedure request-url() +\rules only transcludeinline transcludeblock filteredtranscludeinline filteredtranscludeblock +https://api.zotero.org/groups/{{$:/config/zotero-group}}/items/ +\end request-url + +<$wikify name="url" text=<>> + <$action-sendmessage + $message="tm-http-request" + url=<> + method="GET" + query-format="json" + query-sort="title" + query-start=<> + query-limit=<> + header-accept="application/json" + bind-status="$:/temp/zotero/status" + bind-progress="$:/temp/zotero/progress" + oncompletion=<> + onprogress=<> + var-start=<> + var-limit=<> + /> + +\end + +\procedure zotero-actions() +<$macrocall $name="zotero-get-items" start="0" limit="50"/> +\end + +<> + +<$button actions=<>> +Start import from Zotero group + + +<$button message="tm-http-cancel-all-requests"> +Cancel all HTTP requests + Outstanding requests: {{$:/state/http-requests}} + +<$list filter="[tag[$:/tags/ZoteroImport]limit[1]]" variable="ignore"> + +!! Imported Tiddlers + +<$button> +<$action-deletetiddler $filter="[tag[$:/tags/ZoteroImport]]"/> +Delete these tiddlers + + +Export: <$macrocall $name="exportButton" exportFilter="[tag[$:/tags/ZoteroImport]]" lingoBase="$:/language/Buttons/ExportTiddlers/"/> + + + +
    +<$list filter="[tag[$:/tags/ZoteroImport]]"> +
  1. +<$link> +<$view field="title"/> + +
  2. + +
diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request.tid new file mode 100644 index 000000000..f6c82e760 --- /dev/null +++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-http-request.tid @@ -0,0 +1,51 @@ +caption: tm-http-request +created: 20230429161453032 +modified: 20230429161453032 +tags: Messages +title: WidgetMessage: tm-http-request +type: text/vnd.tiddlywiki + +The ''tm-http-request'' message is used to make an HTTP request to a server. + +It uses the following properties on the `event` object: + +|!Name |!Description | +|param |Not used | +|paramObject |Hashmap of parameters (see below) | + +The following parameters are used: + +|!Name |!Description | +|method |HTTP method (eg "GET", "POST") | +|body |String data to be sent with the request | +|query-* |Query string parameters with string values | +|header-* |Headers with string values | +|password-header-* |Headers with values taken from the password store | +|password-query-* |Query string parameters with values taken from the password store | +|var-* |Variables to be passed to the completion and progress handlers (without the "var-" prefix) | +|bind-status |Title of tiddler to which the status of the request ("pending", "complete", "error") should be bound | +|bind-progress |Title of tiddler to which the progress of the request (0 to 100) should be bound | +|oncompletion |Action strings to be executed when the request completes | +|onprogress |Action strings to be executed when progress is reported | + +The following variables are passed to the completion handler: + +|!Name |!Description | +|status |HTTP result status code (see [[MDN|https://developer.mozilla.org/en-US/docs/Web/HTTP/Status]]) | +|statusText |HTTP result status text | +|error |Error string | +|data |Returned data | +|headers |Response headers as a JSON object | + +The following variables are passed to the progress handler: + +|!Name |!Description | +|lengthComputable |Whether the progress loaded and total figures are valid - "yes" or "no" | +|loaded |Number of bytes loaded so far | +|total |Total number bytes to be loaded | + +Note that the state tiddler $:/state/http-requests contains a number representing the number of outstanding HTTP requests in progress. + +!! Examples + +* [[Zotero's|https://www.zotero.org/]] API for retrieving reference items: [[WidgetMessage: tm-http-request Example - Zotero]] diff --git a/editions/tw5.com/tiddlers/messages/config-zotero-group.tid b/editions/tw5.com/tiddlers/messages/config-zotero-group.tid new file mode 100644 index 000000000..2215c496a --- /dev/null +++ b/editions/tw5.com/tiddlers/messages/config-zotero-group.tid @@ -0,0 +1,2 @@ +title: $:/config/zotero-group +text: 4813312 \ No newline at end of file diff --git a/themes/tiddlywiki/vanilla/base.tid b/themes/tiddlywiki/vanilla/base.tid index 53943f994..a8df11bb3 100644 --- a/themes/tiddlywiki/vanilla/base.tid +++ b/themes/tiddlywiki/vanilla/base.tid @@ -3185,6 +3185,10 @@ span.tc-translink > a:first-child { fill: <>; } +.tc-network-activity-background { + fill: <>; +} + /* ** Flexbox utility classes */ From 106f121133a9c527118231f81a4ab6a14ced988d Mon Sep 17 00:00:00 2001 From: Mario Pietsch Date: Tue, 13 Jun 2023 11:44:34 +0200 Subject: [PATCH 18/94] Table-of-content macros -- make "exclude" an official macro parameter (#7417) * toc make exclude a proper macro parameter using subfilter instead of enlist * add exclude parameter to TOC documentation tiddler * add exclude parameter to toc-tabbed-xx macros * add from-version to exclude parameter --- core/wiki/macros/toc.tid | 26 +++++++++---------- .../tiddlers/macros/TableOfContentsMacro.tid | 16 ++++++++---- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/core/wiki/macros/toc.tid b/core/wiki/macros/toc.tid index 6b8a83295..528c0e63c 100644 --- a/core/wiki/macros/toc.tid +++ b/core/wiki/macros/toc.tid @@ -19,9 +19,9 @@ tags: $:/tags/Macro \define toc-body(tag,sort:"",itemClassFilter,exclude,path) \whitespace trim
    - <$list filter="""[all[shadows+tiddlers]tag<__tag__>!has[draft.of]$sort$] -[<__tag__>] -[enlist<__exclude__>]"""> + <$list filter="""[all[shadows+tiddlers]tag<__tag__>!has[draft.of]$sort$] -[<__tag__>] -[subfilter<__exclude__>]"""> <$let item=<> path={{{ [<__path__>addsuffix[/]addsuffix<__tag__>] }}}> - <$set name="excluded" filter="""[enlist<__exclude__>] [<__tag__>]"""> + <$set name="excluded" filter="[subfilter<__exclude__>] [<__tag__>]"> <$set name="toc-item-class" filter=<<__itemClassFilter__>> emptyValue="toc-item-selected" value="toc-item">
  1. >> <$list filter="[all[current]toc-link[no]]" emptyMessage="<$link to={{{ [get[target]else] }}}><>"> @@ -36,8 +36,8 @@ tags: $:/tags/Macro
\end -\define toc(tag,sort:"",itemClassFilter:"") -<$macrocall $name="toc-body" tag=<<__tag__>> sort=<<__sort__>> itemClassFilter=<<__itemClassFilter__>> /> +\define toc(tag,sort:"",itemClassFilter:"", exclude) +<$macrocall $name="toc-body" tag=<<__tag__>> sort=<<__sort__>> itemClassFilter=<<__itemClassFilter__>> exclude=<<__exclude__>>/> \end \define toc-linked-expandable-body(tag,sort:"",itemClassFilter,exclude,path) @@ -75,7 +75,7 @@ tags: $:/tags/Macro
  • >> <$reveal type="nomatch" stateTitle=<> text="open"> <$button setTitle=<> setTo="open" class="tc-btn-invisible tc-popup-keep"> - <$transclude tiddler=<> /> + <$transclude tiddler=<> /> <> @@ -100,9 +100,9 @@ tags: $:/tags/Macro \define toc-expandable(tag,sort:"",itemClassFilter:"",exclude,path) \whitespace trim <$let tag=<<__tag__>> sort=<<__sort__>> itemClassFilter=<<__itemClassFilter__>> path={{{ [<__path__>addsuffix[/]addsuffix<__tag__>] }}}> - <$set name="excluded" filter="""[enlist<__exclude__>] [<__tag__>]"""> + <$set name="excluded" filter="[subfilter<__exclude__>] [<__tag__>]">
      - <$list filter="""[all[shadows+tiddlers]tag<__tag__>!has[draft.of]$sort$] -[<__tag__>] -[enlist<__exclude__>]"""> + <$list filter="""[all[shadows+tiddlers]tag<__tag__>!has[draft.of]$sort$] -[<__tag__>] -[subfilter<__exclude__>]"""> <$list filter="[all[current]toc-link[no]]" emptyMessage=<> > <$macrocall $name="toc-unlinked-expandable-body" tag=<<__tag__>> sort=<<__sort__>> itemClassFilter="""itemClassFilter""" exclude=<> path=<> /> @@ -174,9 +174,9 @@ tags: $:/tags/Macro \define toc-selective-expandable(tag,sort:"",itemClassFilter,exclude,path) \whitespace trim <$let tag=<<__tag__>> sort=<<__sort__>> itemClassFilter=<<__itemClassFilter__>> path={{{ [<__path__>addsuffix[/]addsuffix<__tag__>] }}}> - <$set name="excluded" filter="[enlist<__exclude__>] [<__tag__>]"> + <$set name="excluded" filter="[subfilter<__exclude__>] [<__tag__>]">
        - <$list filter="""[all[shadows+tiddlers]tag<__tag__>!has[draft.of]$sort$] -[<__tag__>] -[enlist<__exclude__>]"""> + <$list filter="""[all[shadows+tiddlers]tag<__tag__>!has[draft.of]$sort$] -[<__tag__>] -[subfilter<__exclude__>]"""> <$list filter="[all[current]toc-link[no]]" variable="ignore" emptyMessage=<> > <$macrocall $name="toc-unlinked-selective-expandable-body" tag=<<__tag__>> sort=<<__sort__>> itemClassFilter=<<__itemClassFilter__>> exclude=<> path=<>/> @@ -186,13 +186,13 @@ tags: $:/tags/Macro \end -\define toc-tabbed-external-nav(tag,sort:"",selectedTiddler:"$:/temp/toc/selectedTiddler",unselectedText,missingText,template:"") +\define toc-tabbed-external-nav(tag,sort:"",selectedTiddler:"$:/temp/toc/selectedTiddler",unselectedText,missingText,template:"",exclude) \whitespace trim <$tiddler tiddler={{{ [<__selectedTiddler__>get[text]] }}}>
        <$linkcatcher to=<<__selectedTiddler__>>>
        - <$macrocall $name="toc-selective-expandable" tag=<<__tag__>> sort=<<__sort__>> itemClassFilter="[all[current]] -[<__selectedTiddler__>get[text]]"/> + <$macrocall $name="toc-selective-expandable" tag=<<__tag__>> sort=<<__sort__>> itemClassFilter="[all[current]] -[<__selectedTiddler__>get[text]]" exclude=<<__exclude__>>/>
        @@ -210,9 +210,9 @@ tags: $:/tags/Macro \end -\define toc-tabbed-internal-nav(tag,sort:"",selectedTiddler:"$:/temp/toc/selectedTiddler",unselectedText,missingText,template:"") +\define toc-tabbed-internal-nav(tag,sort:"",selectedTiddler:"$:/temp/toc/selectedTiddler",unselectedText,missingText,template:"",exclude) \whitespace trim <$linkcatcher to=<<__selectedTiddler__>>> - <$macrocall $name="toc-tabbed-external-nav" tag=<<__tag__>> sort=<<__sort__>> selectedTiddler=<<__selectedTiddler__>> unselectedText=<<__unselectedText__>> missingText=<<__missingText__>> template=<<__template__>>/> + <$macrocall $name="toc-tabbed-external-nav" tag=<<__tag__>> sort=<<__sort__>> selectedTiddler=<<__selectedTiddler__>> unselectedText=<<__unselectedText__>> missingText=<<__missingText__>> template=<<__template__>> exclude=<<__exclude__>> /> \end diff --git a/editions/tw5.com/tiddlers/macros/TableOfContentsMacro.tid b/editions/tw5.com/tiddlers/macros/TableOfContentsMacro.tid index c813fd1e6..54343bf32 100644 --- a/editions/tw5.com/tiddlers/macros/TableOfContentsMacro.tid +++ b/editions/tw5.com/tiddlers/macros/TableOfContentsMacro.tid @@ -1,5 +1,5 @@ created: 20140919155729620 -modified: 20220819093733569 +modified: 20230427125500432 tags: Macros [[Core Macros]] title: Table-of-Contents Macros type: text/vnd.tiddlywiki @@ -53,15 +53,21 @@ These two parameters are combined into a single [[filter expression|Filter Expre <<.var toc-tabbed-internal-nav>> and <<.var toc-tabbed-external-nav>> take additional parameters: -;selectedTiddler +; selectedTiddler : The title of the [[state tiddler|StateMechanism]] for noting the currently selected tiddler, defaulting to `$:/temp/toc/selectedTiddler`. It is recommended that this be a [[system tiddler|SystemTiddlers]] -;unselectedText + +; unselectedText : The text to display when no tiddler is selected in the tree -;missingText + +; missingText : The text to display if the selected tiddler doesn't exist -;template + +; template : Optionally, the title of a tiddler to use as a [[template|TemplateTiddlers]] for transcluding the selected tiddler into the right-hand panel +; exclude <<.from-version "5.3.0">> +: This optional parameter can be used to exclude tiddlers from the TOC list. It allows a [[Title List]] or a <<.olink subfilter>>. Eg: `exclude:"HelloThere [[Title with spaces]]"` or `exclude:"[has[excludeTOC]]"`. Where the former will exclude two tiddlers and the later would exclude every tiddler that has a field <<.field excludeTOC>> independent of its value.
        ''Be aware'' that eg: `[prefix[H]]` is a shortcut for `[all[tiddlers]prefix[H]]`, which can have a performance impact, if used carelessly. So use $:/AdvancedSearch -> ''Filters'' tab to test the <<.param exclude>> parameter + !! Custom Icons <<.from-version "5.2.4">> From 86d45f1c3d7f617223d1c13e6fd8aa588b13c486 Mon Sep 17 00:00:00 2001 From: btheado Date: Tue, 13 Jun 2023 04:50:00 -0500 Subject: [PATCH 19/94] Request permission to protect local storage from eviction (#7398) * Request the browser to never evict the persistent storage * Store browser storage persisted state in a tiddler * Factor out some code into helper functions * Display status of persistence request in the settings page --- .../tiddlywiki/browser-storage/settings.tid | 10 ++++ plugins/tiddlywiki/browser-storage/startup.js | 49 ++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/plugins/tiddlywiki/browser-storage/settings.tid b/plugins/tiddlywiki/browser-storage/settings.tid index 7bf0e26e5..eb2e27940 100644 --- a/plugins/tiddlywiki/browser-storage/settings.tid +++ b/plugins/tiddlywiki/browser-storage/settings.tid @@ -28,6 +28,16 @@ This setting allows a custom alert message to be displayed when an attempt to st <$link to="$:/config/BrowserStorage/QuotaExceededAlert">Quota Exceeded Alert: <$edit-text tiddler="$:/config/BrowserStorage/QuotaExceededAlert" default="" tag="input" size="50"/> +! Prevent browser from evicting local storage + +Permission for local storage persistence: ''{{$:/info/browser/storage/persisted}}'' + +The first time a tiddler is saved to local storage a request will be made to prevent automatic eviction of local storage for this site. This means the data will not be cleared unless the user manually clears it. + +Old browsers may not support this feature. New browsers might not support the feature if the wiki is hosted on a non-localhost unencrypted http connection. + +Some browsers will explicitly prompt the user for permission. Other browsers may automatically grant or deny the request based on site usage or based on whether the site is bookmarked. + ! Startup Log The tiddler $:/temp/BrowserStorage/Log contains a log of the tiddlers that were loaded from local storage at startup: diff --git a/plugins/tiddlywiki/browser-storage/startup.js b/plugins/tiddlywiki/browser-storage/startup.js index 69cc5119e..552de93d2 100644 --- a/plugins/tiddlywiki/browser-storage/startup.js +++ b/plugins/tiddlywiki/browser-storage/startup.js @@ -19,7 +19,8 @@ exports.after = ["startup"]; exports.synchronous = true; var ENABLED_TITLE = "$:/config/BrowserStorage/Enabled", - SAVE_FILTER_TITLE = "$:/config/BrowserStorage/SaveFilter"; + SAVE_FILTER_TITLE = "$:/config/BrowserStorage/SaveFilter", + PERSISTED_STATE_TITLE = "$:/info/browser/storage/persisted"; var BrowserStorageUtil = require("$:/plugins/tiddlywiki/browser-storage/util.js").BrowserStorageUtil; @@ -53,6 +54,48 @@ exports.startup = function() { $tw.wiki.addTiddler({title: ENABLED_TITLE, text: "no"}); $tw.browserStorage.clearLocalStorage(); }); + // Helpers for protecting storage from eviction + var setPersistedState = function(state) { + $tw.wiki.addTiddler({title: PERSISTED_STATE_TITLE, text: state}); + }, + requestPersistence = function() { + setPersistedState("requested"); + navigator.storage.persist().then(function(persisted) { + console.log("Request for persisted storage " + (persisted ? "granted" : "denied")); + setPersistedState(persisted ? "granted" : "denied"); + }); + }, + persistPermissionRequested = false, + requestPersistenceOnFirstSave = function() { + $tw.hooks.addHook("th-saving-tiddler", function(tiddler) { + if (!persistPermissionRequested) { + var filteredChanges = filterFn.call($tw.wiki, function(iterator) { + iterator(tiddler,tiddler.getFieldString("title")); + }); + if (filteredChanges.length > 0) { + // The tiddler will be saved to local storage, so request persistence + requestPersistence(); + persistPermissionRequested = true; + } + } + return tiddler; + }); + }; + // Request the browser to never evict the localstorage. Some browsers such as firefox + // will prompt the user. To make the decision easier for the user only prompt them + // when they click the save button on a tiddler which will be stored to localstorage. + if (navigator.storage && navigator.storage.persist) { + navigator.storage.persisted().then(function(isPersisted) { + if (!isPersisted) { + setPersistedState("not requested yet"); + requestPersistenceOnFirstSave(); + } else { + setPersistedState("granted"); + } + }); + } else { + setPersistedState("feature not available"); + } // Track tiddler changes $tw.wiki.addEventListener("change",function(changes) { // Bail if browser storage is disabled @@ -76,6 +119,10 @@ exports.startup = function() { if(title === ENABLED_TITLE) { return; } + // This should always be queried from the browser, so don't store it in local storage + if(title === PERSISTED_STATE_TITLE) { + return; + } // Save the tiddler $tw.browserStorage.saveTiddlerToLocalStorage(title); }); From 5947140b61793ef85473e285039e05cf1e4b00d6 Mon Sep 17 00:00:00 2001 From: TonyM <31584658+AnthonyMuscio@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:59:40 +1000 Subject: [PATCH 20/94] Update Using Excise.tid (#7504) Added a comma and fixed a typo --- editions/tw5.com/tiddlers/howtos/Using Excise.tid | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editions/tw5.com/tiddlers/howtos/Using Excise.tid b/editions/tw5.com/tiddlers/howtos/Using Excise.tid index 7d618a3b9..cd916a752 100644 --- a/editions/tw5.com/tiddlers/howtos/Using Excise.tid +++ b/editions/tw5.com/tiddlers/howtos/Using Excise.tid @@ -5,13 +5,13 @@ title: Using Excise type: text/vnd.tiddlywiki ! Excise text -From the EditorToolbar you can export selected text to a new tiddler and insert a [[link|Linking in WikiText]] [[Transclusion]] or [[macro|Macros]] in its place. Click ''Excise text'' (<<.icon $:/core/images/excise>>), input name of the new tiddler, and choose excise method. +From the EditorToolbar you can export selected text to a new tiddler and insert a [[link|Linking in WikiText]], [[Transclusion]] or [[macro|Macros]] in its place. Click ''Excise text'' (<<.icon $:/core/images/excise>>), input name of the new tiddler, and choose excise method. !! How to excise text # Highlight the relevant piece of text # Click ''Excise text'' (<<.icon $:/core/images/excise>>) # Give the new tiddler a title. -# Chosse if the new tiddler will be tagged with the title of the current tiddler (see note below). +# Choose if the new tiddler will be tagged with the title of the current tiddler (see note below). # Choose replacing method: [[link|Linking in WikiText]], [[transclusion|Transclusion]], or [[macro|Macros]]. # Click the ''{{$:/language/Buttons/Excise/Caption/Excise}}'' button From 46d0aea0f219d3686694b2094564b755f97bef0c Mon Sep 17 00:00:00 2001 From: twMat Date: Tue, 13 Jun 2023 12:02:06 +0200 Subject: [PATCH 21/94] Update ShadowTiddlers.tid (updated) (#7518) * Update ShadowTiddlers.tid main change is added section about "overriding shadow tids" * The word "extracted" might be confusing --------- Co-authored-by: jeremy@jermolene.com --- editions/tw5.com/tiddlers/concepts/ShadowTiddlers.tid | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/editions/tw5.com/tiddlers/concepts/ShadowTiddlers.tid b/editions/tw5.com/tiddlers/concepts/ShadowTiddlers.tid index 11abdd2e9..89417bc65 100644 --- a/editions/tw5.com/tiddlers/concepts/ShadowTiddlers.tid +++ b/editions/tw5.com/tiddlers/concepts/ShadowTiddlers.tid @@ -9,9 +9,13 @@ tags: Concepts <$button actions=<>>$text$ \end -ShadowTiddlers are tiddlers that are loaded from within [[Plugins]]. Unlike ordinary tiddlers, they don't appear in most lists. +ShadowTiddlers are tiddlers that are loaded from [[Plugins]] at the wiki startup. Unlike ordinary tiddlers, they don't appear in most lists. -ShadowTiddlers can be overridden with an ordinary tiddler of the same name. If that tiddler is subsequently deleted then the original shadow tiddler is automatically restored. +!! Overriding Shadow Tiddlers to modify plugins + +A ShadowTiddler can be overridden with an ordinary tiddler of the same name. This leaves the shadow tiddler intact but the plugin will use the overriding tiddler in its place, effectively allowing users to modify the behaviour of plugins. + +Users are cautioned against overriding shadow tiddlers because if the shadow tiddler is changed in a plugin update, the overriding tiddler may no longer perform as intended. To remedy this, the overriding tiddler may be modified or deleted. If the overriding tiddler is deleted, then the plugin falls back to using the original shadow tiddler. !! Overridden Shadow Tiddlers From f277493acdaa87f4ee926fef8ebc263abc73f0fb Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Tue, 13 Jun 2023 11:22:11 +0100 Subject: [PATCH 22/94] Improved fix for #7529 The fix in cce23ac6cddbccc88a848dcc5c456e57c01b2c20 was affecting other editor dropdowns --- core/ui/EditorToolbar/link-dropdown.tid | 4 ++-- themes/tiddlywiki/vanilla/base.tid | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/ui/EditorToolbar/link-dropdown.tid b/core/ui/EditorToolbar/link-dropdown.tid index e2766935b..d2887a180 100644 --- a/core/ui/EditorToolbar/link-dropdown.tid +++ b/core/ui/EditorToolbar/link-dropdown.tid @@ -18,7 +18,7 @@ title: $:/core/ui/EditorToolbar/link-dropdown \define external-link() \whitespace trim -<$button class="tc-btn-invisible" style="width: auto; display: inline-block; background-colour: inherit;" actions=<>> +<$button class="tc-btn-invisible tc-btn-mini" style="width: auto; display: inline-block; background-colour: inherit;" actions=<>> {{$:/core/images/chevron-right}} \end @@ -45,7 +45,7 @@ title: $:/core/ui/EditorToolbar/link-dropdown <$reveal tag="span" state=<> type="nomatch" text=""> <> -<$button class="tc-btn-invisible" style="width: auto; display: inline-block; background-colour: inherit;"> +<$button class="tc-btn-invisible tc-btn-mini" style="width: auto; display: inline-block; background-colour: inherit;"> <><$set name="cssEscapedTitle" value={{{ [escapecss[]] }}}><$action-sendmessage $message="tm-focus-selector" $param=<>/> {{$:/core/images/close-button}} diff --git a/themes/tiddlywiki/vanilla/base.tid b/themes/tiddlywiki/vanilla/base.tid index a8df11bb3..dcf4a1697 100644 --- a/themes/tiddlywiki/vanilla/base.tid +++ b/themes/tiddlywiki/vanilla/base.tid @@ -1388,9 +1388,8 @@ html body.tc-body.tc-single-tiddler-window { height: 1.2em; } -.tc-editor-toolbar .tc-drop-down a, -.tc-editor-toolbar .tc-drop-down button { - padding: 0; +.tc-editor-toolbar .tc-drop-down button.tc-btn-mini { + padding: 2px 4px; } .tc-editor-toolbar button:hover { From 120c2f8136440ddc0e48656205e04ef837a9f8b7 Mon Sep 17 00:00:00 2001 From: Bram Chen Date: Tue, 13 Jun 2023 21:50:20 +0800 Subject: [PATCH 23/94] Update chinese language files (#7536) * Add chinese translations for the new network activity button --- languages/zh-Hans/Buttons.multids | 2 ++ languages/zh-Hant/Buttons.multids | 2 ++ 2 files changed, 4 insertions(+) diff --git a/languages/zh-Hans/Buttons.multids b/languages/zh-Hans/Buttons.multids index a94a31940..f33169778 100644 --- a/languages/zh-Hans/Buttons.multids +++ b/languages/zh-Hans/Buttons.multids @@ -67,6 +67,8 @@ More/Caption: 更多 More/Hint: 更多操作 NewHere/Caption: 添加子条目 NewHere/Hint: 创建一个标签为此条目名称的新条目 +NetworkActivity/Caption: 网络活动 +NetworkActivity/Hint: 取消所有网络活动 NewJournal/Caption: 添加日志 NewJournal/Hint: 创建一个新的日志条目 NewJournalHere/Caption: 添加子日志 diff --git a/languages/zh-Hant/Buttons.multids b/languages/zh-Hant/Buttons.multids index 7ffc15f50..cc5ebba6b 100644 --- a/languages/zh-Hant/Buttons.multids +++ b/languages/zh-Hant/Buttons.multids @@ -67,6 +67,8 @@ More/Caption: 更多 More/Hint: 更多動作 NewHere/Caption: 新增子條目 NewHere/Hint: 建立一個標籤為此條目名稱的新條目 +NetworkActivity/Caption: 網路活動 +NetworkActivity/Hint: 取消所有網路活動 NewJournal/Caption: 新增日誌 NewJournal/Hint: 建立一個新的日誌條目 NewJournalHere/Caption: 新增子日誌 From 50315310f530a3c081e7f986aa169f57e628bba2 Mon Sep 17 00:00:00 2001 From: buggyj Date: Tue, 13 Jun 2023 16:55:44 +0200 Subject: [PATCH 24/94] Add widget.destroy() function (#7468) --- core/modules/widgets/widget.js | 35 +++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index c0d2bc7a6..8ffee0ab7 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -718,23 +718,44 @@ Widget.prototype.findFirstDomNode = function() { }; /* -Remove any DOM nodes created by this widget or its children +Entry into destroy procedure +*/ +Widget.prototype.destroyChildren = function() { + $tw.utils.each(this.children,function(childWidget) { + childWidget.destroy(); + }); +}; +/* +Legacy entry into destroy procedure */ Widget.prototype.removeChildDomNodes = function() { - // If this widget has directly created DOM nodes, delete them and exit. This assumes that any child widgets are contained within the created DOM nodes, which would normally be the case + this.destroy(); +}; +/* +Default destroy +*/ +Widget.prototype.destroy = function() { + // call children to remove their resources + this.destroyChildren(); + // remove our resources + this.children = []; + this.removeLocalDomNodes(); +}; + +/* +Remove any DOM nodes created by this widget +*/ +Widget.prototype.removeLocalDomNodes = function() { + // If this widget has directly created DOM nodes, delete them and exit. if(this.domNodes.length > 0) { $tw.utils.each(this.domNodes,function(domNode) { domNode.parentNode.removeChild(domNode); }); this.domNodes = []; - } else { - // Otherwise, ask the child widgets to delete their DOM nodes - $tw.utils.each(this.children,function(childWidget) { - childWidget.removeChildDomNodes(); - }); } }; + /* Invoke the action widgets that are descendents of the current widget. */ From 12f7b98c4fba93b6d7db2157a2b8ba03e1fd02a4 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Tue, 13 Jun 2023 22:57:24 +0800 Subject: [PATCH 25/94] Docs for widget.destroy (#7508) --- .../Widget `destroy` method examples.tid | 36 +++++++++++++++++ .../moduletypes/WidgetModules.tid | 13 ++++-- editions/dev/tiddlers/system/doc-styles.tid | 40 +++++++++++++++++++ .../dev/tiddlers/system/version-macros.tid | 14 +++++++ 4 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 editions/dev/tiddlers/Widget `destroy` method examples.tid create mode 100644 editions/dev/tiddlers/system/doc-styles.tid create mode 100644 editions/dev/tiddlers/system/version-macros.tid diff --git a/editions/dev/tiddlers/Widget `destroy` method examples.tid b/editions/dev/tiddlers/Widget `destroy` method examples.tid new file mode 100644 index 000000000..5ff04bdd0 --- /dev/null +++ b/editions/dev/tiddlers/Widget `destroy` method examples.tid @@ -0,0 +1,36 @@ +created: 20230601123245916 +modified: 20230601125015463 +title: Widget `destroy` method examples +type: text/vnd.tiddlywiki + +!! When using a v-dom library + +Virtual DOM libraries manages its internal state and apply state to DOM periodically, this is so called [["controlled" component|https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components]]. When Tiddlywiki remove a DOM element controlled by a v-dom library, it may throws error. + +So when creating a plugin providing v-dom library binding, you need to tell v-dom library (for example, React.js) the DOM element is removed. We will use `destroy` method for this. + +```js + render() { + // ...other render related code + if (this.root === undefined || this.containerElement === undefined) { + // initialize the v-dom library + this.root = ReactDom.createRoot(document.createElement('div')); + } + } + + destroy() { + // end the lifecycle of v-dom library + this.root && this.root.unmount(); + } +``` + +The `destroy` method will be called by parent widget. If you widget don't have any child widget, you can just write your own tear down logic. If it may have some child widget, don't forget to call original `destroy` method in the `Widget` class to destroy children widgets. + +```js +Widget.prototype.destroy(); +this.root && this.root.unmount(); +/** if you are using ESNext +super.destroy(); +this.root?.unmount(); +*/ +``` \ No newline at end of file diff --git a/editions/dev/tiddlers/from tw5.com/moduletypes/WidgetModules.tid b/editions/dev/tiddlers/from tw5.com/moduletypes/WidgetModules.tid index 1a8bf5edf..0b0b3f33a 100644 --- a/editions/dev/tiddlers/from tw5.com/moduletypes/WidgetModules.tid +++ b/editions/dev/tiddlers/from tw5.com/moduletypes/WidgetModules.tid @@ -1,7 +1,8 @@ -title: WidgetModules +created: 20131101130700000 +modified: 20230601130631884 tags: dev moduletypes -created: 201311011307 -modified: 201311011307 +title: WidgetModules +type: text/vnd.tiddlywiki ! Introduction @@ -78,4 +79,10 @@ The individual methods defined by the widget object are documented in the source !! Widget `refreshChildren` method !! Widget `findNextSiblingDomNode` method !! Widget `findFirstDomNode` method +!! Widget `destroy` method + +<<.from-version "5.3.0">> Gets called when any parent widget is unmounted from the widget tree. + +[[Examples|Widget `destroy` method examples]] + !! Widget `removeChildDomNodes` method diff --git a/editions/dev/tiddlers/system/doc-styles.tid b/editions/dev/tiddlers/system/doc-styles.tid new file mode 100644 index 000000000..24234d47a --- /dev/null +++ b/editions/dev/tiddlers/system/doc-styles.tid @@ -0,0 +1,40 @@ +created: 20150117152612000 +modified: 20230325101137075 +tags: $:/tags/Stylesheet +title: $:/editions/tw5.com/doc-styles +type: text/vnd.tiddlywiki + +a.doc-from-version.tc-tiddlylink { + display: inline-block; + border-radius: 1em; + background: <>; + color: <>; + fill: <>; + padding: 0 0.4em; + font-size: 0.7em; + text-transform: uppercase; + font-weight: bold; + line-height: 1.5; + vertical-align: text-bottom; +} + +a.doc-deprecated-version.tc-tiddlylink { + display: inline-block; + border-radius: 1em; + background: red; + color: <>; + fill: <>; + padding: 0 0.4em; + font-size: 0.7em; + text-transform: uppercase; + font-weight: bold; + line-height: 1.5; + vertical-align: text-bottom; +} + +.doc-deprecated-version svg, +.doc-from-version svg { + width: 1em; + height: 1em; + vertical-align: text-bottom; +} diff --git a/editions/dev/tiddlers/system/version-macros.tid b/editions/dev/tiddlers/system/version-macros.tid new file mode 100644 index 000000000..0fb7dcf12 --- /dev/null +++ b/editions/dev/tiddlers/system/version-macros.tid @@ -0,0 +1,14 @@ +code-body: yes +created: 20161008085627406 +modified: 20221007122259593 +tags: $:/tags/Macro +title: $:/editions/tw5.com/version-macros +type: text/vnd.tiddlywiki + +\define .from-version(version) +<$link to={{{ [<__version__>addprefix[Release ]] }}} class="doc-from-version">{{$:/core/images/warning}} New in: <$text text=<<__version__>>/> +\end + +\define .deprecated-since(version, superseded:"TODO-Link") +<$link to="Deprecated - What does it mean" class="doc-deprecated-version tc-btn-invisible">{{$:/core/images/warning}} Deprecated since: <$text text=<<__version__>>/> (see <$link to=<<__superseded__>>><$text text=<<__superseded__>>/>) +\end From f90eb386ae7cd7da0f18b8d53fb0e454d9486d75 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Tue, 13 Jun 2023 16:36:07 +0100 Subject: [PATCH 26/94] Bidirectional text improvements (#4541) * Add support for \dir pragma * Add "dir" attribute to reveal, edit, edit-text and edit-codemirror widgets * Add $:/config/DefaultTextDirection hidden setting * Revert accidentally commited test data This reverts some of commit b83c1d160f12813a499872126d637b7f2199a29b. * Remove Codemirror plugin from Prerelease Makes it easier to test things * Fix framed text editor directionality in Firefox * Add direction attribute for edit body template * Missed closing brace * Add docs for \dir pragma * Templates should set text direction from a variable, not a transclusion * Updates to framed.js in the light of PRs that have been merged since this * Restore whitespace trim * Docs dates * Fix typo * Clarify docs --- core/modules/editor/engines/framed.js | 4 ++ core/modules/editor/engines/simple.js | 3 ++ core/modules/editor/factory.js | 3 +- core/modules/parsers/wikiparser/rules/dir.js | 51 +++++++++++++++++++ core/modules/parsers/wikiparser/wikiparser.js | 1 + core/modules/widgets/edit.js | 3 +- core/modules/widgets/reveal.js | 6 ++- core/templates/single.tiddler.window.tid | 3 +- core/ui/EditTemplate.tid | 1 + core/ui/EditTemplate/body-editor.tid | 1 + core/ui/EditTemplate/body/default.tid | 4 +- core/ui/EditTemplate/controls.tid | 2 +- core/ui/EditTemplate/fields.tid | 4 +- core/ui/EditTemplate/shadow.tid | 4 +- core/ui/EditTemplate/tags.tid | 2 +- core/ui/EditTemplate/title.tid | 6 +-- core/ui/EditTemplate/type.tid | 2 +- core/ui/PageTemplate.tid | 3 +- core/ui/ViewTemplate.tid | 2 +- core/ui/ViewTemplate/body.tid | 2 +- core/ui/ViewTemplate/subtitle.tid | 2 +- core/ui/ViewTemplate/tags.tid | 2 +- core/ui/ViewTemplate/title.tid | 2 +- core/wiki/config/DefaultTextDirection.tid | 2 + .../tiddlers/Right-To-Left Languages.tid | 11 ++++ .../tw5.com/tiddlers/pragmas/Pragma_ _dir.tid | 13 +++++ plugins/tiddlywiki/codemirror/engine.js | 3 ++ 27 files changed, 120 insertions(+), 22 deletions(-) create mode 100644 core/modules/parsers/wikiparser/rules/dir.js create mode 100644 core/wiki/config/DefaultTextDirection.tid create mode 100644 editions/tw5.com/tiddlers/Right-To-Left Languages.tid create mode 100644 editions/tw5.com/tiddlers/pragmas/Pragma_ _dir.tid diff --git a/core/modules/editor/engines/framed.js b/core/modules/editor/engines/framed.js index a4cf983b0..01b9974c2 100644 --- a/core/modules/editor/engines/framed.js +++ b/core/modules/editor/engines/framed.js @@ -72,6 +72,9 @@ function FramedEngine(options) { if(this.widget.editRows) { this.domNode.setAttribute("rows",this.widget.editRows); } + if(this.widget.editDir) { + this.domNode.setAttribute("dir",this.widget.editDir); + } if(this.widget.editTabIndex) { this.iframeNode.setAttribute("tabindex",this.widget.editTabIndex); } @@ -120,6 +123,7 @@ FramedEngine.prototype.copyStyles = function() { this.domNode.style["-webkit-text-fill-color"] = "currentcolor"; // Ensure we don't force text direction to LTR this.domNode.style.removeProperty("direction"); + this.domNode.style.removeProperty("unicodeBidi"); }; /* diff --git a/core/modules/editor/engines/simple.js b/core/modules/editor/engines/simple.js index 9840cb623..64c087133 100644 --- a/core/modules/editor/engines/simple.js +++ b/core/modules/editor/engines/simple.js @@ -52,6 +52,9 @@ function SimpleEngine(options) { if(this.widget.editTabIndex) { this.domNode.setAttribute("tabindex",this.widget.editTabIndex); } + if(this.widget.editDir) { + this.domNode.setAttribute("dir",this.widget.editDir); + } if(this.widget.editAutoComplete) { this.domNode.setAttribute("autocomplete",this.widget.editAutoComplete); } diff --git a/core/modules/editor/factory.js b/core/modules/editor/factory.js index 6157ec67f..7e43f709b 100644 --- a/core/modules/editor/factory.js +++ b/core/modules/editor/factory.js @@ -183,6 +183,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) { this.editFocusSelectFromStart = $tw.utils.parseNumber(this.getAttribute("focusSelectFromStart","0")); this.editFocusSelectFromEnd = $tw.utils.parseNumber(this.getAttribute("focusSelectFromEnd","0")); this.editTabIndex = this.getAttribute("tabindex"); + this.editDir = this.getAttribute("dir"); this.editCancelPopups = this.getAttribute("cancelPopups","") === "yes"; this.editInputActions = this.getAttribute("inputActions"); this.editRefreshTitle = this.getAttribute("refreshTitle"); @@ -220,7 +221,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) { EditTextWidget.prototype.refresh = function(changedTiddlers) { var changedAttributes = this.computeAttributes(); // Completely rerender if any of our attributes have changed - if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) { + if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.dir || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) { this.refreshSelf(); return true; } else if (changedTiddlers[this.editRefreshTitle]) { diff --git a/core/modules/parsers/wikiparser/rules/dir.js b/core/modules/parsers/wikiparser/rules/dir.js new file mode 100644 index 000000000..e30fe7a47 --- /dev/null +++ b/core/modules/parsers/wikiparser/rules/dir.js @@ -0,0 +1,51 @@ +/*\ +title: $:/core/modules/parsers/wikiparser/rules/dir.js +type: application/javascript +module-type: wikirule + +Wiki pragma rule for specifying text direction + +``` +\dir rtl +\dir ltr +\dir auto +``` + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +exports.name = "dir"; +exports.types = {pragma: true}; + +/* +Instantiate parse rule +*/ +exports.init = function(parser) { + this.parser = parser; + // Regexp to match + this.matchRegExp = /^\\dir[^\S\n]*(\S+)\r?\n/mg; +}; + +/* +Parse the most recent match +*/ +exports.parse = function() { + var self = this; + // Move past the pragma invocation + this.parser.pos = this.matchRegExp.lastIndex; + // Parse tree nodes to return + return [{ + type: "element", + tag: this.parser.parseAsInline ? "span" : "div", + attributes: { + dir: {type: "string", value: this.match[1]} + }, + children: [] + }]; +}; + +})(); diff --git a/core/modules/parsers/wikiparser/wikiparser.js b/core/modules/parsers/wikiparser/wikiparser.js index bb457b205..9cdb91913 100644 --- a/core/modules/parsers/wikiparser/wikiparser.js +++ b/core/modules/parsers/wikiparser/wikiparser.js @@ -36,6 +36,7 @@ options: see below: */ var WikiParser = function(type,text,options) { this.wiki = options.wiki; + this.parseAsInline = options.parseAsInline; var self = this; // Check for an externally linked tiddler if($tw.browser && (text || "") === "" && options._canonical_uri) { diff --git a/core/modules/widgets/edit.js b/core/modules/widgets/edit.js index e7bd49b93..ce72f0926 100644 --- a/core/modules/widgets/edit.js +++ b/core/modules/widgets/edit.js @@ -48,6 +48,7 @@ EditWidget.prototype.execute = function() { this.editPlaceholder = this.getAttribute("placeholder"); this.editTabIndex = this.getAttribute("tabindex"); this.editFocus = this.getAttribute("focus",""); + this.editDir = this.getAttribute("dir"); this.editCancelPopups = this.getAttribute("cancelPopups",""); this.editInputActions = this.getAttribute("inputActions"); this.editRefreshTitle = this.getAttribute("refreshTitle"); @@ -90,7 +91,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of EditWidget.prototype.refresh = function(changedTiddlers) { var changedAttributes = this.computeAttributes(); // Refresh if an attribute has changed, or the type associated with the target tiddler has changed - if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) { + if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tabindex || changedAttributes.dir || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) { this.refreshSelf(); return true; } else { diff --git a/core/modules/widgets/reveal.js b/core/modules/widgets/reveal.js index 3e3510f75..fde810439 100755 --- a/core/modules/widgets/reveal.js +++ b/core/modules/widgets/reveal.js @@ -42,6 +42,9 @@ RevealWidget.prototype.render = function(parent,nextSibling) { if(this.style) { domNode.setAttribute("style",this.style); } + if(this.direction) { + domNode.setAttribute("dir",this.direction); + } parent.insertBefore(domNode,nextSibling); this.renderChildren(domNode,null); if(!domNode.isTiddlyWikiFakeDom && this.type === "popup" && this.isOpen) { @@ -123,6 +126,7 @@ RevealWidget.prototype.execute = function() { this["default"] = this.getAttribute("default",""); this.animate = this.getAttribute("animate","no"); this.retain = this.getAttribute("retain","no"); + this.direction = this.getAttribute("dir"); this.openAnimation = this.animate === "no" ? undefined : "open"; this.closeAnimation = this.animate === "no" ? undefined : "close"; this.updatePopupPosition = this.getAttribute("updatePopupPosition","no") === "yes"; @@ -214,7 +218,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of */ RevealWidget.prototype.refresh = function(changedTiddlers) { var changedAttributes = this.computeAttributes(); - if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes.positionAllowNegative || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex) { + if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes.positionAllowNegative || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex || changedAttributes.dir) { this.refreshSelf(); return true; } else { diff --git a/core/templates/single.tiddler.window.tid b/core/templates/single.tiddler.window.tid index aa5175c01..48ce49247 100644 --- a/core/templates/single.tiddler.window.tid +++ b/core/templates/single.tiddler.window.tid @@ -12,7 +12,8 @@ tc-page-container tc-page-view-$(storyviewTitle)$ tc-language-$(languageTitle)$ tv-config-toolbar-class={{$:/config/Toolbar/ButtonClass}} tv-show-missing-links={{$:/config/MissingLinks}} storyviewTitle={{$:/view}} - languageTitle={{{ [{$:/language}get[name]] }}}> + languageTitle={{{ [{$:/language}get[name]] }}} + tv-text-direction={{$:/config/DefaultTextDirection}}>
        >> diff --git a/core/ui/EditTemplate.tid b/core/ui/EditTemplate.tid index 5aed61a73..4ddea2a62 100644 --- a/core/ui/EditTemplate.tid +++ b/core/ui/EditTemplate.tid @@ -29,6 +29,7 @@ title: $:/core/ui/EditTemplate data-tiddler-title=<> data-tags={{!!tags}} class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/TiddlerTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-tiddler-frame tc-tiddler-edit-frame [is[tiddler]then[tc-tiddler-exists]] [is[missing]!is[shadow]then[tc-tiddler-missing]] [is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [is[system]then[tc-tiddler-system]] [{!!class}] [tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}} + dir=<> role="region" aria-label={{$:/language/EditTemplate/Caption}}> <$fieldmangler> diff --git a/core/ui/EditTemplate/body-editor.tid b/core/ui/EditTemplate/body-editor.tid index 374567acd..8d17c498e 100644 --- a/core/ui/EditTemplate/body-editor.tid +++ b/core/ui/EditTemplate/body-editor.tid @@ -9,6 +9,7 @@ title: $:/core/ui/EditTemplate/body/editor placeholder={{$:/language/EditTemplate/Body/Placeholder}} tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[text]then[true]] ~[[false]] }}} + dir=<> cancelPopups="yes" fileDrop={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} diff --git a/core/ui/EditTemplate/body/default.tid b/core/ui/EditTemplate/body/default.tid index a2128efb0..069a43d1a 100644 --- a/core/ui/EditTemplate/body/default.tid +++ b/core/ui/EditTemplate/body/default.tid @@ -15,7 +15,7 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$ importState=<> > <$dropzone importTitle=<> autoOpenOnImport="no" contentTypesFilter={{$:/config/Editor/ImportContentTypesFilter}} class="tc-dropzone-editor" enable={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} filesOnly="yes" actions=<> > <$reveal stateTitle=<> type="match" text="yes" tag="div"> -
        +
        >> <$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/> @@ -32,7 +32,7 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
        -<$reveal stateTitle=<> type="nomatch" text="yes" tag="div"> +<$reveal stateTitle=<> type="nomatch" text="yes" tag="div" dir=<>> <$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/> diff --git a/core/ui/EditTemplate/controls.tid b/core/ui/EditTemplate/controls.tid index 3e94d371d..2dd8709ae 100644 --- a/core/ui/EditTemplate/controls.tid +++ b/core/ui/EditTemplate/controls.tid @@ -5,7 +5,7 @@ tags: $:/tags/EditTemplate $:/config/EditToolbarButtons/Visibility/$(listItem)$ \end \whitespace trim -
        +
        >> <$view field="title"/> <$list filter="[all[shadows+tiddlers]tag[$:/tags/EditToolbar]!has[draft.of]]" variable="listItem"><$let tv-config-toolbar-class={{{ [enlist] [encodeuricomponent[]addprefix[tc-btn-]] +[join[ ]]}}}><$reveal type="nomatch" state=<> text="hide"><$transclude tiddler=<>/>
        diff --git a/core/ui/EditTemplate/fields.tid b/core/ui/EditTemplate/fields.tid index 6a767517b..438456455 100644 --- a/core/ui/EditTemplate/fields.tid +++ b/core/ui/EditTemplate/fields.tid @@ -74,7 +74,7 @@ $value={{{ [subfilterget[text]] }}}/> \whitespace trim <$set name="newFieldValueTiddlerPrefix" value=<> emptyValue=<> > -
        +
        >> <$list filter="[all[current]fields[]] +[sort[title]]" variable="currentField" storyview="pop"> @@ -101,7 +101,7 @@ $value={{{ [subfilterget[text]] }}}/> <$fieldmangler> -
        +
        >> <> diff --git a/core/ui/EditTemplate/shadow.tid b/core/ui/EditTemplate/shadow.tid index 3ae3e0a1f..97672750e 100644 --- a/core/ui/EditTemplate/shadow.tid +++ b/core/ui/EditTemplate/shadow.tid @@ -14,7 +14,7 @@ tags: $:/tags/EditTemplate <$list filter="[all[current]shadowsource[]]" variable="pluginTitle"> <$set name="pluginLink" value=<>> -
        +
        >> <> @@ -29,7 +29,7 @@ tags: $:/tags/EditTemplate <$list filter="[all[current]shadowsource[]]" variable="pluginTitle"> <$set name="pluginLink" value=<>> -
        +
        >> <> diff --git a/core/ui/EditTemplate/tags.tid b/core/ui/EditTemplate/tags.tid index 5084478b4..0456e1bb7 100644 --- a/core/ui/EditTemplate/tags.tid +++ b/core/ui/EditTemplate/tags.tid @@ -27,7 +27,7 @@ color:$(foregroundColor)$; \define edit-tags-template(tagField:"tags") \whitespace trim -
        +
        >> <$list filter="[list[!!$tagField$]sort[title]]" storyview="pop"> <$macrocall $name="tag-body" colour={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} palette={{$:/palette}} icon={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} tagField=<<__tagField__>>/> diff --git a/core/ui/EditTemplate/title.tid b/core/ui/EditTemplate/title.tid index 5228ad7c0..fa02db819 100644 --- a/core/ui/EditTemplate/title.tid +++ b/core/ui/EditTemplate/title.tid @@ -2,13 +2,13 @@ title: $:/core/ui/EditTemplate/title tags: $:/tags/EditTemplate \whitespace trim -<$edit-text field="draft.title" class="tc-titlebar tc-edit-texteditor" focus={{{ [{$:/config/AutoFocus}match[title]then[true]] ~[[false]] }}} tabindex={{$:/config/EditTabIndex}} cancelPopups="yes"/> +<$edit-text field="draft.title" class="tc-titlebar tc-edit-texteditor" focus={{{ [{$:/config/AutoFocus}match[title]then[true]] ~[[false]] }}} tabindex={{$:/config/EditTabIndex}} cancelPopups="yes" dir=<>/> <$vars pattern="""[\|\[\]{}]""" bad-chars="""`| [ ] { }`"""> <$list filter="[all[current]regexp:draft.title]" variable="listItem"> -
        +
        >> {{$:/core/images/warning}} {{$:/language/EditTemplate/Title/BadCharacterWarning}} @@ -18,7 +18,7 @@ tags: $:/tags/EditTemplate -<$reveal state="!!draft.title" type="nomatch" text={{!!draft.of}} tag="div"> +<$reveal state="!!draft.title" type="nomatch" text={{!!draft.of}} tag="div" dir=<>> <$list filter="[{!!draft.title}!is[missing]]" variable="listItem"> diff --git a/core/ui/EditTemplate/type.tid b/core/ui/EditTemplate/type.tid index faa89639f..0dca582e1 100644 --- a/core/ui/EditTemplate/type.tid +++ b/core/ui/EditTemplate/type.tid @@ -9,7 +9,7 @@ first-search-filter: [all[shadows+tiddlers]prefix[$:/language/Docs/Types/]sort[d
        <>
        -
        <$fieldmangler> +
        >}><$fieldmangler> <$macrocall $name="keyboard-driven-input" tiddler=<> storeTitle=<> refreshTitle=<> selectionStateTitle=<> field="type" tag="input" default="" placeholder={{$:/language/EditTemplate/Type/Placeholder}} focusPopup=<> class="tc-edit-typeeditor tc-edit-texteditor tc-popup-handle" tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[type]then[true]] ~[[false]] }}} cancelPopups="yes" configTiddlerFilter="[[$:/core/ui/EditTemplate/type]]" inputCancelActions=<>/><$button popup=<> class="tc-btn-invisible tc-btn-dropdown tc-small-gap" tooltip={{$:/language/EditTemplate/Type/Dropdown/Hint}} aria-label={{$:/language/EditTemplate/Type/Dropdown/Caption}}>{{$:/core/images/down-arrow}}<$button message="tm-remove-field" param="type" class="tc-btn-invisible tc-btn-icon" tooltip={{$:/language/EditTemplate/Type/Delete/Hint}} aria-label={{$:/language/EditTemplate/Type/Delete/Caption}}>{{$:/core/images/delete-button}}<$action-deletetiddler $filter="[] [] []"/>
        diff --git a/core/ui/PageTemplate.tid b/core/ui/PageTemplate.tid index f0ab4852a..faf1a06b6 100644 --- a/core/ui/PageTemplate.tid +++ b/core/ui/PageTemplate.tid @@ -13,7 +13,8 @@ icon: $:/core/images/layout-button tv-enable-drag-and-drop={{$:/config/DragAndDrop/Enable}} tv-show-missing-links={{$:/config/MissingLinks}} storyviewTitle={{$:/view}} - languageTitle={{{ [{$:/language}get[name]] }}}> + languageTitle={{{ [{$:/language}get[name]] }}} + tv-text-direction={{$:/config/DefaultTextDirection}}>
        ] [[tc-language-]addsuffix] :and[unique[]join[ ]] }}} > diff --git a/core/ui/ViewTemplate.tid b/core/ui/ViewTemplate.tid index dcba5c953..3f39f3496 100644 --- a/core/ui/ViewTemplate.tid +++ b/core/ui/ViewTemplate.tid @@ -7,7 +7,7 @@ $:/state/folded/$(currentTiddler)$ \define cancel-delete-tiddler-actions(message) <$action-sendmessage $message="tm-$message$-tiddler"/> \import [all[shadows+tiddlers]tag[$:/tags/Macro/View]!is[draft]] [all[shadows+tiddlers]tag[$:/tags/Global/View]!is[draft]] <$vars storyTiddler=<> tiddlerInfoState=<>> -
        > data-tags={{!!tags}} class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/TiddlerTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-tiddler-frame tc-tiddler-view-frame [is[tiddler]then[tc-tiddler-exists]] [is[missing]!is[shadow]then[tc-tiddler-missing]] [is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [is[system]then[tc-tiddler-system]] [{!!class}] [tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}} role="article"> +
        > data-tiddler-title=<> data-tags={{!!tags}} class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/TiddlerTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-tiddler-frame tc-tiddler-view-frame [is[tiddler]then[tc-tiddler-exists]] [is[missing]!is[shadow]then[tc-tiddler-missing]] [is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [is[system]then[tc-tiddler-system]] [{!!class}] [tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}} role="article"> <$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate]!is[draft]]" variable="listItem"> <$transclude tiddler=<>/> diff --git a/core/ui/ViewTemplate/body.tid b/core/ui/ViewTemplate/body.tid index 34e6aaa38..36cac1e18 100644 --- a/core/ui/ViewTemplate/body.tid +++ b/core/ui/ViewTemplate/body.tid @@ -3,7 +3,7 @@ tags: $:/tags/ViewTemplate \import [all[shadows+tiddlers]tag[$:/tags/Macro/View/Body]!is[draft]] [all[shadows+tiddlers]tag[$:/tags/Global/View/Body]!is[draft]] -<$reveal tag="div" class="tc-tiddler-body" type="nomatch" stateTitle=<> text="hide" retain="yes" animate="yes"> +<$reveal tag="div" class="tc-tiddler-body" type="nomatch" stateTitle=<> text="hide" retain="yes" animate="yes" dir=<>> <$transclude tiddler={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/ViewTemplateBodyFilter]!is[draft]get[text]] :and[!is[blank]else[$:/core/ui/ViewTemplate/body/default]] }}} /> diff --git a/core/ui/ViewTemplate/subtitle.tid b/core/ui/ViewTemplate/subtitle.tid index a0436b095..611130869 100644 --- a/core/ui/ViewTemplate/subtitle.tid +++ b/core/ui/ViewTemplate/subtitle.tid @@ -3,7 +3,7 @@ tags: $:/tags/ViewTemplate \whitespace trim <$reveal type="nomatch" stateTitle=<> text="hide" tag="div" retain="yes" animate="yes"> -
        +
        >> <$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate/Subtitle]!has[draft.of]]" variable="subtitleTiddler" counter="indexSubtitleTiddler"> <$list filter="[match[no]]" variable="ignore">   diff --git a/core/ui/ViewTemplate/tags.tid b/core/ui/ViewTemplate/tags.tid index d1f4e55c9..95b5dbe39 100644 --- a/core/ui/ViewTemplate/tags.tid +++ b/core/ui/ViewTemplate/tags.tid @@ -3,5 +3,5 @@ tags: $:/tags/ViewTemplate \whitespace trim <$reveal type="nomatch" stateTitle=<> text="hide" tag="div" retain="yes" animate="yes"> -
        <$list filter="[all[current]tags[]sort[title]]" template="$:/core/ui/TagTemplate" storyview="pop"/>
        +
        >><$list filter="[all[current]tags[]sort[title]]" template="$:/core/ui/TagTemplate" storyview="pop"/>
        diff --git a/core/ui/ViewTemplate/title.tid b/core/ui/ViewTemplate/title.tid index 98695f6bf..19d375068 100644 --- a/core/ui/ViewTemplate/title.tid +++ b/core/ui/ViewTemplate/title.tid @@ -6,7 +6,7 @@ tags: $:/tags/ViewTemplate fill:$(foregroundColor)$; \end
        -
        +
        >> <$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewToolbar]!has[draft.of]] :filter[lookup[$:/config/ViewToolbarButtons/Visibility/]!match[hide]]" storyview="pop" variable="listItem"><$set name="tv-config-toolbar-class" filter="[] [encodeuricomponent[]addprefix[tc-btn-]]"><$transclude tiddler=<>/> diff --git a/core/wiki/config/DefaultTextDirection.tid b/core/wiki/config/DefaultTextDirection.tid new file mode 100644 index 000000000..6140bbf7b --- /dev/null +++ b/core/wiki/config/DefaultTextDirection.tid @@ -0,0 +1,2 @@ +title: $:/config/DefaultTextDirection +text: auto diff --git a/editions/tw5.com/tiddlers/Right-To-Left Languages.tid b/editions/tw5.com/tiddlers/Right-To-Left Languages.tid new file mode 100644 index 000000000..d32d01524 --- /dev/null +++ b/editions/tw5.com/tiddlers/Right-To-Left Languages.tid @@ -0,0 +1,11 @@ +created: 20230613162508509 +modified: 20230613162508509 +title: Right-To-Left Languages +type: text/vnd.tiddlywiki + +<<.from-version "5.3.0">> The [[language plugins|Languages]] in TiddlyWiki's plugin library apply the appropriate [["right-to-left" setting|https://www.w3.org/International/questions/qa-html-dir]] to the entire document. To set the right to left setting independently for an individual tiddler, use the `\dir` [[pragma|Pragma]] at the top of the tiddler: + +``` +\dir rtl +This text will be displayed with right-to-left formatting +``` diff --git a/editions/tw5.com/tiddlers/pragmas/Pragma_ _dir.tid b/editions/tw5.com/tiddlers/pragmas/Pragma_ _dir.tid new file mode 100644 index 000000000..bc5774e30 --- /dev/null +++ b/editions/tw5.com/tiddlers/pragmas/Pragma_ _dir.tid @@ -0,0 +1,13 @@ +created: 20230613162508509 +modified: 20230613162508509 +tags: Pragmas +title: Pragma: \dir +type: text/vnd.tiddlywiki + +<<.from-version "5.3.0">> The ''\dir'' [[pragma|Pragmas]] is used to set the text direction of text within a tiddler -- see [[Right-To-Left Languages]]. + +The ''\dir'' pragma should be used after any procedure, function, widget or macro definitions. + +* `\dir ltr` – sets text direction to left-to-right +* `\dir rtl` – sets text direction to right-to-left +* `\dir auto` – causes the browser to attempt to automatically deduce the text direction diff --git a/plugins/tiddlywiki/codemirror/engine.js b/plugins/tiddlywiki/codemirror/engine.js index e775e1c95..e8749481d 100755 --- a/plugins/tiddlywiki/codemirror/engine.js +++ b/plugins/tiddlywiki/codemirror/engine.js @@ -109,6 +109,9 @@ function CodeMirrorEngine(options) { if(this.widget.editTabIndex) { config["tabindex"] = this.widget.editTabIndex; } + if(this.widget.editDir) { + config.direction = this.widget.editDir; + } config.editWidget = this.widget; // Create the CodeMirror instance this.cm = window.CodeMirror(function(cmDomNode) { From 73b23f48a08cbef2d56946955a557fc760b5b581 Mon Sep 17 00:00:00 2001 From: Maurycy Zarzycki Date: Wed, 14 Jun 2023 08:42:49 +0200 Subject: [PATCH 27/94] Polish Translations 2023-06-14 (#7540) * Add Polish translations for strings introduced in 2221b8e08a572b4899081cb86e7f9a1dd57adf11 * Add Polish translations for strings changed in 98e72558d03ba5242d847265525f62dc93d434a5 * Add Polish translations for strings changed in d1f90f075f7cf41531f5e967b02acbc244885904 --- languages/pl-PL/Buttons.multids | 2 ++ languages/pl-PL/Misc.multids | 2 ++ languages/pl-PL/SiteTitle.tid | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/languages/pl-PL/Buttons.multids b/languages/pl-PL/Buttons.multids index 8d5fa3465..911559337 100644 --- a/languages/pl-PL/Buttons.multids +++ b/languages/pl-PL/Buttons.multids @@ -67,6 +67,8 @@ More/Caption: więcej More/Hint: Więcej akcji NewHere/Caption: nowy tiddler tu NewHere/Hint: Stwórz nowego tiddlera otagowanego tym tiddlerem +NetworkActivity/Caption: ruch sieciowy +NetworkActivity/Hint: Anuluj cały ruch sieciowy NewJournal/Caption: nowy dziennik NewJournal/Hint: Tworzy nowego tiddlera o typie dziennika NewJournalHere/Caption: nowy dziennik tu diff --git a/languages/pl-PL/Misc.multids b/languages/pl-PL/Misc.multids index 1dee7fe68..211798bc8 100644 --- a/languages/pl-PL/Misc.multids +++ b/languages/pl-PL/Misc.multids @@ -25,6 +25,8 @@ Encryption/RepeatPassword: Powtórz hasło Encryption/PasswordNoMatch: Hasła się nie zgadzają Encryption/SetPassword: Ustaw hasło Error/Caption: Bład +Error/DeserializeOperator/MissingOperand: Błąd filtra: Nie podano argumentu dla operatora 'deserialize' +Error/DeserializeOperator/UnknownDeserializer: Błąd filtra: Podano nieznany deserializator jako argument dla operatora 'deserialize' Error/Filter: Bład filtra Error/FilterSyntax: Bład składniowy filtra Error/FilterRunPrefix: Bład filtra: Nieznany prefiks dla filtra 'run' diff --git a/languages/pl-PL/SiteTitle.tid b/languages/pl-PL/SiteTitle.tid index 13af3bb3b..7fbd5a790 100644 --- a/languages/pl-PL/SiteTitle.tid +++ b/languages/pl-PL/SiteTitle.tid @@ -1,3 +1,3 @@ title: $:/SiteTitle -Moja ~TiddlyWiki +Moja TiddlyWiki From b61c01d8b0bf90ef012fe4ef12cab3624f6362fb Mon Sep 17 00:00:00 2001 From: cdruan <80615570+cdruan@users.noreply.github.com> Date: Wed, 14 Jun 2023 01:55:16 -0700 Subject: [PATCH 28/94] Update widget name policy (#7510) --- plugins/tiddlywiki/markdown/markdown-it-tiddlywiki.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/tiddlywiki/markdown/markdown-it-tiddlywiki.js b/plugins/tiddlywiki/markdown/markdown-it-tiddlywiki.js index 7870cb8c4..64189ba8b 100644 --- a/plugins/tiddlywiki/markdown/markdown-it-tiddlywiki.js +++ b/plugins/tiddlywiki/markdown/markdown-it-tiddlywiki.js @@ -200,7 +200,7 @@ function tw_filteredtranscludeinline(state,silent) { } // based on markdown-it html_block() -var WidgetTagRegEx = [/^<\/?\$[a-zA-Z0-9\-\$]+(?=(\s|\/?>|$))/, /^$/]; +var WidgetTagRegEx = [/^<\/?\$[a-zA-Z0-9\-\$\.]+(?=(\s|\/?>|$))/, /^$/]; function tw_block(state,startLine,endLine,silent) { var i, nextLine, token, lineText, pos = state.bMarks[startLine] + state.tShift[startLine], @@ -364,7 +364,7 @@ function tw_prettyextlink(state,silent) { return true; } -var TWCloseTagRegEx = /<\/\$[A-Za-z0-9\-\$]+\s*>/gm; +var TWCloseTagRegEx = /<\/\$[A-Za-z0-9\-\$\.]+\s*>/gm; function extendHtmlInline(origRule) { return function(state,silent) { if(origRule(state,silent)) { From edaa3727d976f4a5efa2468726480880f5ca8dcc Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Wed, 14 Jun 2023 09:59:18 +0100 Subject: [PATCH 29/94] Update Release 5.3.0.tid --- editions/prerelease/tiddlers/Release 5.3.0.tid | 1 - 1 file changed, 1 deletion(-) diff --git a/editions/prerelease/tiddlers/Release 5.3.0.tid b/editions/prerelease/tiddlers/Release 5.3.0.tid index db7e3a3b9..cf1ce0098 100644 --- a/editions/prerelease/tiddlers/Release 5.3.0.tid +++ b/editions/prerelease/tiddlers/Release 5.3.0.tid @@ -83,7 +83,6 @@ Improvements to the following translations: * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7529">> size of buttons in dropdown for editor "link" toolbar button * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/8e132948b6bec623d81d300fbe6dc3a0307bcc6d">> crash when transcluding a lazily loaded tiddler as an attribute value * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7462">> DiffTextWidget crash with missing or empty attributes -* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7448">> CheckboxWidget to avoid writing to date fields ! Developer Improvements From f4626aa69e39fb439cad674aea596ab7fc5b15c4 Mon Sep 17 00:00:00 2001 From: Saq Imtiaz Date: Wed, 14 Jun 2023 18:57:43 +0200 Subject: [PATCH 30/94] Fix: Fix tests for deserialize[] so they can be run on browser as well as node.js (#7543) --- editions/test/tiddlers/tests/test-filters.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/editions/test/tiddlers/tests/test-filters.js b/editions/test/tiddlers/tests/test-filters.js index 1ffc73f17..811bbaa55 100644 --- a/editions/test/tiddlers/tests/test-filters.js +++ b/editions/test/tiddlers/tests/test-filters.js @@ -1066,7 +1066,11 @@ Tests the filtering mechanism. }); it("should handle the deserializers operator", function() { - expect(wiki.filterTiddlers("[deserializers[]]").join(",")).toBe("application/javascript,application/json,application/x-tiddler,application/x-tiddler-html-div,application/x-tiddlers,text/css,text/html,text/plain"); + var expectedDeserializers = ["application/javascript","application/json","application/x-tiddler","application/x-tiddler-html-div","application/x-tiddlers","text/css","text/html","text/plain"]; + if($tw.browser) { + expectedDeserializers.unshift("(DOM)"); + } + expect(wiki.filterTiddlers("[deserializers[]]").join(",")).toBe(expectedDeserializers.join(",")); }); it("should handle the charcode operator", function() { From 5bef6d50bc367cf4c9a3b98dd2fdc792a0603c10 Mon Sep 17 00:00:00 2001 From: btheado Date: Thu, 15 Jun 2023 05:10:25 -0500 Subject: [PATCH 31/94] Removed stale reference to double dollar signs for custom widgets (#7546) --- editions/tw5.com/tiddlers/variables/Variable Usage.tid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editions/tw5.com/tiddlers/variables/Variable Usage.tid b/editions/tw5.com/tiddlers/variables/Variable Usage.tid index bc5f36443..9db23a456 100644 --- a/editions/tw5.com/tiddlers/variables/Variable Usage.tid +++ b/editions/tw5.com/tiddlers/variables/Variable Usage.tid @@ -151,4 +151,4 @@ Below is an example macro, procedure and function definition. All three forms o *''variables'' - \define, <<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>, \procedure, \widget, \function all create variables. If the same name is used, then later define will overwrite earlier defined *''<<.op function>> filter operator parameter'' - only variables defined using \function can be called using the <<.olink function>> operator *''filter operators'' - only the [[javascript defined filter operators|Filter Operators]] and variables defined using \function with name containing a dot can be called - *''widgets'' - variables defined using \widget can be invoked using `<$widget/>` syntax ONLY if the name starts a dollar sign (to override existing javascript defined widgets) or double dollar sign (to define [[custom widgets|Custom Widgets]]). Without the dollar sign prefix, defining variables using \widget is no different than using \procedure. + *''widgets'' - variables defined using \widget can be invoked using `<$widget/>` syntax ONLY if the name starts a dollar sign. Without the dollar sign prefix, defining variables using \widget is no different than using \procedure. From 190613ad2989f70526f86eef17f524087f60eb72 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Sat, 17 Jun 2023 08:58:15 +0100 Subject: [PATCH 32/94] Add tv-config-static variable for indicating static rendering --- core/templates/exporters/StaticRiver.tid | 1 + core/templates/server/static.tiddler.html.tid | 1 + core/templates/static.template.html.tid | 1 + core/templates/static.tiddler.html.tid | 1 + .../tiddlers/variables/tv-config-static Variable.tid | 10 ++++++++++ 5 files changed, 14 insertions(+) create mode 100644 editions/tw5.com/tiddlers/variables/tv-config-static Variable.tid diff --git a/core/templates/exporters/StaticRiver.tid b/core/templates/exporters/StaticRiver.tid index a22cfb98a..3b70c9d11 100644 --- a/core/templates/exporters/StaticRiver.tid +++ b/core/templates/exporters/StaticRiver.tid @@ -3,6 +3,7 @@ tags: $:/tags/Exporter description: {{$:/language/Exporters/StaticRiver}} extension: .html +\define tv-config-static() yes \define tv-wikilink-template() #$uri_encoded$ \define tv-config-toolbar-icons() no \define tv-config-toolbar-text() no diff --git a/core/templates/server/static.tiddler.html.tid b/core/templates/server/static.tiddler.html.tid index a8409e50f..6c9fd80a5 100644 --- a/core/templates/server/static.tiddler.html.tid +++ b/core/templates/server/static.tiddler.html.tid @@ -1,6 +1,7 @@ title: $:/core/templates/server/static.tiddler.html \whitespace trim +\define tv-config-static() yes \define tv-wikilink-template() $uri_encoded$ \import [subfilter{$:/core/config/GlobalImportFilter}] diff --git a/core/templates/static.template.html.tid b/core/templates/static.template.html.tid index 5da5fb752..8b6482846 100644 --- a/core/templates/static.template.html.tid +++ b/core/templates/static.template.html.tid @@ -1,6 +1,7 @@ title: $:/core/templates/static.template.html type: text/vnd.tiddlywiki-html +\define tv-config-static() yes \define tv-wikilink-template() static/$uri_doubleencoded$.html \define tv-config-toolbar-icons() no \define tv-config-toolbar-text() no diff --git a/core/templates/static.tiddler.html.tid b/core/templates/static.tiddler.html.tid index f90818464..a3297ee78 100644 --- a/core/templates/static.tiddler.html.tid +++ b/core/templates/static.tiddler.html.tid @@ -1,6 +1,7 @@ title: $:/core/templates/static.tiddler.html \define tv-wikilink-template() $uri_doubleencoded$.html +\define tv-config-static() yes \define tv-config-toolbar-icons() no \define tv-config-toolbar-text() no \define tv-config-toolbar-class() tc-btn-invisible diff --git a/editions/tw5.com/tiddlers/variables/tv-config-static Variable.tid b/editions/tw5.com/tiddlers/variables/tv-config-static Variable.tid new file mode 100644 index 000000000..1534c9fb5 --- /dev/null +++ b/editions/tw5.com/tiddlers/variables/tv-config-static Variable.tid @@ -0,0 +1,10 @@ +created: 20230617085524754 +modified: 20230617085524754 +title: tv-config-static Variable +tags: Variables [[Core Variables]] [[Configuration Variables]] +type: text/vnd.tiddlywiki +caption: tv-config-static + +<<.from-version "5.3.0">> The <<.def tv-config-static>> [[variable|Variables]] is set to `yes` within static rendering templates, and is unset in other contexts. + +It is useful for selectively hiding or showing content depending on whether a rendering is static or interactive. From d8124ee82da224ca640be411cbb90fdfa2378db0 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Sat, 17 Jun 2023 08:58:50 +0100 Subject: [PATCH 33/94] Menu bar plugin: Hide menu bar in static renderings Fixes #7476 --- plugins/tiddlywiki/menubar/menu.tid | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/tiddlywiki/menubar/menu.tid b/plugins/tiddlywiki/menubar/menu.tid index 1d592cbfa..473416891 100644 --- a/plugins/tiddlywiki/menubar/menu.tid +++ b/plugins/tiddlywiki/menubar/menu.tid @@ -42,6 +42,7 @@ tags: $:/tags/PageTemplate \end +<$list filter="[!match[yes]]" variable="ignore"> <$list filter="[all[shadows+tiddlers]tag[$:/tags/MenuBar]!has[draft.of]] -[all[tiddlers+shadows]tag[$:/tags/TopLeftBar]limit[1]then[]else[$:/plugins/tiddlywiki/menubar/items/topleftbar]] -[all[tiddlers+shadows]tag[$:/tags/TopRightBar]limit[1]then[]else[$:/plugins/tiddlywiki/menubar/items/toprightbar]] +[limit[1]]" variable="listItem"> + From b90c9ef9a08ad63e8a00f90a1e89a79688cb613b Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Sat, 17 Jun 2023 10:32:44 +0100 Subject: [PATCH 34/94] Transclude widget should only create double underscore variables for macros and ordinary variables Fixes #7544 --- core/modules/widgets/transclude.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/modules/widgets/transclude.js b/core/modules/widgets/transclude.js index 1117598de..9902f7632 100755 --- a/core/modules/widgets/transclude.js +++ b/core/modules/widgets/transclude.js @@ -178,7 +178,6 @@ TranscludeWidget.prototype.getTransclusionTarget = function() { srcVariable = variableInfo && variableInfo.srcVariable; if(variableInfo.text) { if(srcVariable.isFunctionDefinition) { - // Function to return parameters by name or position var result = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || ""; parser = { tree: [{ @@ -235,7 +234,7 @@ TranscludeWidget.prototype.getTransclusionTarget = function() { } $tw.utils.addAttributeToParseTreeNode(parser.tree[0],name,param["default"]) }); - } else { + } else if(srcVariable.isMacroDefinition || !srcVariable.isFunctionDefinition) { // For macros and ordinary variables, wrap the parse tree in a vars widget assigning the parameters to variables named "__paramname__" parser = { tree: [ From 13a895bd2daddabdfaadb04e20dbc7563c9c39be Mon Sep 17 00:00:00 2001 From: btheado Date: Sun, 18 Jun 2023 05:05:06 -0500 Subject: [PATCH 35/94] Remove text subst from operator example macro (#7550) * Removed textual substitution from .operator-example macro * Convert .operator-example from macro to procedure --- .../tw5.com/tiddlers/system/operator-macros.tid | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/editions/tw5.com/tiddlers/system/operator-macros.tid b/editions/tw5.com/tiddlers/system/operator-macros.tid index d24cac016..afa0593b1 100644 --- a/editions/tw5.com/tiddlers/system/operator-macros.tid +++ b/editions/tw5.com/tiddlers/system/operator-macros.tid @@ -1,17 +1,17 @@ created: 20150117152607000 -modified: 20220227210111054 +modified: 20230617183916622 tags: $:/tags/Macro title: $:/editions/tw5.com/operator-macros \define .operator-examples(op,text:"Examples") <$link to="$op$ Operator (Examples)">$text$ -\define .operator-example-tryit-actions() <$action-setfield $tiddler=<<.state>> text="show" filter=<<__eg__>>/> -\define .operator-example(n,eg,ie) +\procedure .operator-example-tryit-actions() <$action-setfield $tiddler=<<.state>> text="show" filter=<>/> +\procedure .operator-example(n,eg,ie)
        -<$list filter="[title<.state-prefix>addsuffix{!!title}addsuffix[/]addsuffix[$n$]]" variable=".state"> +<$list filter="[title<.state-prefix>addsuffix{!!title}addsuffix[/]addsuffix]" variable=".state"> <$reveal state=<<.state>> type="nomatch" text="show"> - `$eg$` - <$macrocall $name=".if" cond="""$ie$""" then="""
        → $ie$
        """/> + <$text text=<>/> + <$macrocall $name=".if" cond=<> then={{{[[
        → ]addsuffixaddsuffix[
        ]]}}}/>
        <$button actions=<<.operator-example-tryit-actions>>>Try it
        @@ -21,7 +21,7 @@ title: $:/editions/tw5.com/operator-macros
        <$button set=<<.state>> setTo="">Hide - <$reveal stateTitle=<<.state>> stateField="filter" type="nomatch" text=<<__eg__>>> + <$reveal stateTitle=<<.state>> stateField="filter" type="nomatch" text=<>> <$button actions=<<.operator-example-tryit-actions>>>Reset
        From 6fd2139376b607667796709e188f992adc41c416 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Tue, 20 Jun 2023 15:43:13 +0100 Subject: [PATCH 36/94] Use empty edition to create empty.html and empty.hta Fixes #7555 --- bin/build-site.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-site.sh b/bin/build-site.sh index a9133c2b7..a54d16452 100755 --- a/bin/build-site.sh +++ b/bin/build-site.sh @@ -107,7 +107,7 @@ node $TW5_BUILD_TIDDLYWIKI \ # /empty.html Empty # /empty.hta For Internet Explorer node $TW5_BUILD_TIDDLYWIKI \ - $TW5_BUILD_MAIN_EDITION \ + ./editions/empty \ --verbose \ --output $TW5_BUILD_OUTPUT \ --build empty \ From a05302da10de8404ca5aff793c661260673c4dfd Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Wed, 21 Jun 2023 17:13:33 +0100 Subject: [PATCH 37/94] Revert "Bidirectional text improvements (#4541)" This reverts commit f90eb386ae7cd7da0f18b8d53fb0e454d9486d75. --- core/modules/editor/engines/framed.js | 4 -- core/modules/editor/engines/simple.js | 3 -- core/modules/editor/factory.js | 3 +- core/modules/parsers/wikiparser/rules/dir.js | 51 ------------------- core/modules/parsers/wikiparser/wikiparser.js | 1 - core/modules/widgets/edit.js | 3 +- core/modules/widgets/reveal.js | 6 +-- core/templates/single.tiddler.window.tid | 3 +- core/ui/EditTemplate.tid | 1 - core/ui/EditTemplate/body-editor.tid | 1 - core/ui/EditTemplate/body/default.tid | 4 +- core/ui/EditTemplate/controls.tid | 2 +- core/ui/EditTemplate/fields.tid | 4 +- core/ui/EditTemplate/shadow.tid | 4 +- core/ui/EditTemplate/tags.tid | 2 +- core/ui/EditTemplate/title.tid | 6 +-- core/ui/EditTemplate/type.tid | 2 +- core/ui/PageTemplate.tid | 3 +- core/ui/ViewTemplate.tid | 2 +- core/ui/ViewTemplate/body.tid | 2 +- core/ui/ViewTemplate/subtitle.tid | 2 +- core/ui/ViewTemplate/tags.tid | 2 +- core/ui/ViewTemplate/title.tid | 2 +- core/wiki/config/DefaultTextDirection.tid | 2 - .../tiddlers/Right-To-Left Languages.tid | 11 ---- .../tw5.com/tiddlers/pragmas/Pragma_ _dir.tid | 13 ----- plugins/tiddlywiki/codemirror/engine.js | 3 -- 27 files changed, 22 insertions(+), 120 deletions(-) delete mode 100644 core/modules/parsers/wikiparser/rules/dir.js delete mode 100644 core/wiki/config/DefaultTextDirection.tid delete mode 100644 editions/tw5.com/tiddlers/Right-To-Left Languages.tid delete mode 100644 editions/tw5.com/tiddlers/pragmas/Pragma_ _dir.tid diff --git a/core/modules/editor/engines/framed.js b/core/modules/editor/engines/framed.js index 01b9974c2..a4cf983b0 100644 --- a/core/modules/editor/engines/framed.js +++ b/core/modules/editor/engines/framed.js @@ -72,9 +72,6 @@ function FramedEngine(options) { if(this.widget.editRows) { this.domNode.setAttribute("rows",this.widget.editRows); } - if(this.widget.editDir) { - this.domNode.setAttribute("dir",this.widget.editDir); - } if(this.widget.editTabIndex) { this.iframeNode.setAttribute("tabindex",this.widget.editTabIndex); } @@ -123,7 +120,6 @@ FramedEngine.prototype.copyStyles = function() { this.domNode.style["-webkit-text-fill-color"] = "currentcolor"; // Ensure we don't force text direction to LTR this.domNode.style.removeProperty("direction"); - this.domNode.style.removeProperty("unicodeBidi"); }; /* diff --git a/core/modules/editor/engines/simple.js b/core/modules/editor/engines/simple.js index 64c087133..9840cb623 100644 --- a/core/modules/editor/engines/simple.js +++ b/core/modules/editor/engines/simple.js @@ -52,9 +52,6 @@ function SimpleEngine(options) { if(this.widget.editTabIndex) { this.domNode.setAttribute("tabindex",this.widget.editTabIndex); } - if(this.widget.editDir) { - this.domNode.setAttribute("dir",this.widget.editDir); - } if(this.widget.editAutoComplete) { this.domNode.setAttribute("autocomplete",this.widget.editAutoComplete); } diff --git a/core/modules/editor/factory.js b/core/modules/editor/factory.js index 7e43f709b..6157ec67f 100644 --- a/core/modules/editor/factory.js +++ b/core/modules/editor/factory.js @@ -183,7 +183,6 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) { this.editFocusSelectFromStart = $tw.utils.parseNumber(this.getAttribute("focusSelectFromStart","0")); this.editFocusSelectFromEnd = $tw.utils.parseNumber(this.getAttribute("focusSelectFromEnd","0")); this.editTabIndex = this.getAttribute("tabindex"); - this.editDir = this.getAttribute("dir"); this.editCancelPopups = this.getAttribute("cancelPopups","") === "yes"; this.editInputActions = this.getAttribute("inputActions"); this.editRefreshTitle = this.getAttribute("refreshTitle"); @@ -221,7 +220,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) { EditTextWidget.prototype.refresh = function(changedTiddlers) { var changedAttributes = this.computeAttributes(); // Completely rerender if any of our attributes have changed - if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.dir || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) { + if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) { this.refreshSelf(); return true; } else if (changedTiddlers[this.editRefreshTitle]) { diff --git a/core/modules/parsers/wikiparser/rules/dir.js b/core/modules/parsers/wikiparser/rules/dir.js deleted file mode 100644 index e30fe7a47..000000000 --- a/core/modules/parsers/wikiparser/rules/dir.js +++ /dev/null @@ -1,51 +0,0 @@ -/*\ -title: $:/core/modules/parsers/wikiparser/rules/dir.js -type: application/javascript -module-type: wikirule - -Wiki pragma rule for specifying text direction - -``` -\dir rtl -\dir ltr -\dir auto -``` - -\*/ -(function(){ - -/*jslint node: true, browser: true */ -/*global $tw: false */ -"use strict"; - -exports.name = "dir"; -exports.types = {pragma: true}; - -/* -Instantiate parse rule -*/ -exports.init = function(parser) { - this.parser = parser; - // Regexp to match - this.matchRegExp = /^\\dir[^\S\n]*(\S+)\r?\n/mg; -}; - -/* -Parse the most recent match -*/ -exports.parse = function() { - var self = this; - // Move past the pragma invocation - this.parser.pos = this.matchRegExp.lastIndex; - // Parse tree nodes to return - return [{ - type: "element", - tag: this.parser.parseAsInline ? "span" : "div", - attributes: { - dir: {type: "string", value: this.match[1]} - }, - children: [] - }]; -}; - -})(); diff --git a/core/modules/parsers/wikiparser/wikiparser.js b/core/modules/parsers/wikiparser/wikiparser.js index 9cdb91913..bb457b205 100644 --- a/core/modules/parsers/wikiparser/wikiparser.js +++ b/core/modules/parsers/wikiparser/wikiparser.js @@ -36,7 +36,6 @@ options: see below: */ var WikiParser = function(type,text,options) { this.wiki = options.wiki; - this.parseAsInline = options.parseAsInline; var self = this; // Check for an externally linked tiddler if($tw.browser && (text || "") === "" && options._canonical_uri) { diff --git a/core/modules/widgets/edit.js b/core/modules/widgets/edit.js index ce72f0926..e7bd49b93 100644 --- a/core/modules/widgets/edit.js +++ b/core/modules/widgets/edit.js @@ -48,7 +48,6 @@ EditWidget.prototype.execute = function() { this.editPlaceholder = this.getAttribute("placeholder"); this.editTabIndex = this.getAttribute("tabindex"); this.editFocus = this.getAttribute("focus",""); - this.editDir = this.getAttribute("dir"); this.editCancelPopups = this.getAttribute("cancelPopups",""); this.editInputActions = this.getAttribute("inputActions"); this.editRefreshTitle = this.getAttribute("refreshTitle"); @@ -91,7 +90,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of EditWidget.prototype.refresh = function(changedTiddlers) { var changedAttributes = this.computeAttributes(); // Refresh if an attribute has changed, or the type associated with the target tiddler has changed - if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tabindex || changedAttributes.dir || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) { + if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) { this.refreshSelf(); return true; } else { diff --git a/core/modules/widgets/reveal.js b/core/modules/widgets/reveal.js index fde810439..3e3510f75 100755 --- a/core/modules/widgets/reveal.js +++ b/core/modules/widgets/reveal.js @@ -42,9 +42,6 @@ RevealWidget.prototype.render = function(parent,nextSibling) { if(this.style) { domNode.setAttribute("style",this.style); } - if(this.direction) { - domNode.setAttribute("dir",this.direction); - } parent.insertBefore(domNode,nextSibling); this.renderChildren(domNode,null); if(!domNode.isTiddlyWikiFakeDom && this.type === "popup" && this.isOpen) { @@ -126,7 +123,6 @@ RevealWidget.prototype.execute = function() { this["default"] = this.getAttribute("default",""); this.animate = this.getAttribute("animate","no"); this.retain = this.getAttribute("retain","no"); - this.direction = this.getAttribute("dir"); this.openAnimation = this.animate === "no" ? undefined : "open"; this.closeAnimation = this.animate === "no" ? undefined : "close"; this.updatePopupPosition = this.getAttribute("updatePopupPosition","no") === "yes"; @@ -218,7 +214,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of */ RevealWidget.prototype.refresh = function(changedTiddlers) { var changedAttributes = this.computeAttributes(); - if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes.positionAllowNegative || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex || changedAttributes.dir) { + if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes.positionAllowNegative || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex) { this.refreshSelf(); return true; } else { diff --git a/core/templates/single.tiddler.window.tid b/core/templates/single.tiddler.window.tid index 48ce49247..aa5175c01 100644 --- a/core/templates/single.tiddler.window.tid +++ b/core/templates/single.tiddler.window.tid @@ -12,8 +12,7 @@ tc-page-container tc-page-view-$(storyviewTitle)$ tc-language-$(languageTitle)$ tv-config-toolbar-class={{$:/config/Toolbar/ButtonClass}} tv-show-missing-links={{$:/config/MissingLinks}} storyviewTitle={{$:/view}} - languageTitle={{{ [{$:/language}get[name]] }}} - tv-text-direction={{$:/config/DefaultTextDirection}}> + languageTitle={{{ [{$:/language}get[name]] }}}>
        >> diff --git a/core/ui/EditTemplate.tid b/core/ui/EditTemplate.tid index 4ddea2a62..5aed61a73 100644 --- a/core/ui/EditTemplate.tid +++ b/core/ui/EditTemplate.tid @@ -29,7 +29,6 @@ title: $:/core/ui/EditTemplate data-tiddler-title=<> data-tags={{!!tags}} class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/TiddlerTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-tiddler-frame tc-tiddler-edit-frame [is[tiddler]then[tc-tiddler-exists]] [is[missing]!is[shadow]then[tc-tiddler-missing]] [is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [is[system]then[tc-tiddler-system]] [{!!class}] [tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}} - dir=<> role="region" aria-label={{$:/language/EditTemplate/Caption}}> <$fieldmangler> diff --git a/core/ui/EditTemplate/body-editor.tid b/core/ui/EditTemplate/body-editor.tid index 8d17c498e..374567acd 100644 --- a/core/ui/EditTemplate/body-editor.tid +++ b/core/ui/EditTemplate/body-editor.tid @@ -9,7 +9,6 @@ title: $:/core/ui/EditTemplate/body/editor placeholder={{$:/language/EditTemplate/Body/Placeholder}} tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[text]then[true]] ~[[false]] }}} - dir=<> cancelPopups="yes" fileDrop={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} diff --git a/core/ui/EditTemplate/body/default.tid b/core/ui/EditTemplate/body/default.tid index 069a43d1a..a2128efb0 100644 --- a/core/ui/EditTemplate/body/default.tid +++ b/core/ui/EditTemplate/body/default.tid @@ -15,7 +15,7 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$ importState=<> > <$dropzone importTitle=<> autoOpenOnImport="no" contentTypesFilter={{$:/config/Editor/ImportContentTypesFilter}} class="tc-dropzone-editor" enable={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} filesOnly="yes" actions=<> > <$reveal stateTitle=<> type="match" text="yes" tag="div"> -
        >> +
        <$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/> @@ -32,7 +32,7 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
        -<$reveal stateTitle=<> type="nomatch" text="yes" tag="div" dir=<>> +<$reveal stateTitle=<> type="nomatch" text="yes" tag="div"> <$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/> diff --git a/core/ui/EditTemplate/controls.tid b/core/ui/EditTemplate/controls.tid index 2dd8709ae..3e94d371d 100644 --- a/core/ui/EditTemplate/controls.tid +++ b/core/ui/EditTemplate/controls.tid @@ -5,7 +5,7 @@ tags: $:/tags/EditTemplate $:/config/EditToolbarButtons/Visibility/$(listItem)$ \end \whitespace trim -
        >> +
        <$view field="title"/> <$list filter="[all[shadows+tiddlers]tag[$:/tags/EditToolbar]!has[draft.of]]" variable="listItem"><$let tv-config-toolbar-class={{{ [enlist] [encodeuricomponent[]addprefix[tc-btn-]] +[join[ ]]}}}><$reveal type="nomatch" state=<> text="hide"><$transclude tiddler=<>/>
        diff --git a/core/ui/EditTemplate/fields.tid b/core/ui/EditTemplate/fields.tid index 438456455..6a767517b 100644 --- a/core/ui/EditTemplate/fields.tid +++ b/core/ui/EditTemplate/fields.tid @@ -74,7 +74,7 @@ $value={{{ [subfilterget[text]] }}}/> \whitespace trim <$set name="newFieldValueTiddlerPrefix" value=<> emptyValue=<> > -
        >> +
        <$list filter="[all[current]fields[]] +[sort[title]]" variable="currentField" storyview="pop"> @@ -101,7 +101,7 @@ $value={{{ [subfilterget[text]] }}}/> <$fieldmangler> -
        >> +
        <> diff --git a/core/ui/EditTemplate/shadow.tid b/core/ui/EditTemplate/shadow.tid index 97672750e..3ae3e0a1f 100644 --- a/core/ui/EditTemplate/shadow.tid +++ b/core/ui/EditTemplate/shadow.tid @@ -14,7 +14,7 @@ tags: $:/tags/EditTemplate <$list filter="[all[current]shadowsource[]]" variable="pluginTitle"> <$set name="pluginLink" value=<>> -
        >> +
        <> @@ -29,7 +29,7 @@ tags: $:/tags/EditTemplate <$list filter="[all[current]shadowsource[]]" variable="pluginTitle"> <$set name="pluginLink" value=<>> -
        >> +
        <> diff --git a/core/ui/EditTemplate/tags.tid b/core/ui/EditTemplate/tags.tid index 0456e1bb7..5084478b4 100644 --- a/core/ui/EditTemplate/tags.tid +++ b/core/ui/EditTemplate/tags.tid @@ -27,7 +27,7 @@ color:$(foregroundColor)$; \define edit-tags-template(tagField:"tags") \whitespace trim -
        >> +
        <$list filter="[list[!!$tagField$]sort[title]]" storyview="pop"> <$macrocall $name="tag-body" colour={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} palette={{$:/palette}} icon={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} tagField=<<__tagField__>>/> diff --git a/core/ui/EditTemplate/title.tid b/core/ui/EditTemplate/title.tid index fa02db819..5228ad7c0 100644 --- a/core/ui/EditTemplate/title.tid +++ b/core/ui/EditTemplate/title.tid @@ -2,13 +2,13 @@ title: $:/core/ui/EditTemplate/title tags: $:/tags/EditTemplate \whitespace trim -<$edit-text field="draft.title" class="tc-titlebar tc-edit-texteditor" focus={{{ [{$:/config/AutoFocus}match[title]then[true]] ~[[false]] }}} tabindex={{$:/config/EditTabIndex}} cancelPopups="yes" dir=<>/> +<$edit-text field="draft.title" class="tc-titlebar tc-edit-texteditor" focus={{{ [{$:/config/AutoFocus}match[title]then[true]] ~[[false]] }}} tabindex={{$:/config/EditTabIndex}} cancelPopups="yes"/> <$vars pattern="""[\|\[\]{}]""" bad-chars="""`| [ ] { }`"""> <$list filter="[all[current]regexp:draft.title]" variable="listItem"> -
        >> +
        {{$:/core/images/warning}} {{$:/language/EditTemplate/Title/BadCharacterWarning}} @@ -18,7 +18,7 @@ tags: $:/tags/EditTemplate -<$reveal state="!!draft.title" type="nomatch" text={{!!draft.of}} tag="div" dir=<>> +<$reveal state="!!draft.title" type="nomatch" text={{!!draft.of}} tag="div"> <$list filter="[{!!draft.title}!is[missing]]" variable="listItem"> diff --git a/core/ui/EditTemplate/type.tid b/core/ui/EditTemplate/type.tid index 0dca582e1..faa89639f 100644 --- a/core/ui/EditTemplate/type.tid +++ b/core/ui/EditTemplate/type.tid @@ -9,7 +9,7 @@ first-search-filter: [all[shadows+tiddlers]prefix[$:/language/Docs/Types/]sort[d
        <>
        -
        >}><$fieldmangler> +
        <$fieldmangler> <$macrocall $name="keyboard-driven-input" tiddler=<> storeTitle=<> refreshTitle=<> selectionStateTitle=<> field="type" tag="input" default="" placeholder={{$:/language/EditTemplate/Type/Placeholder}} focusPopup=<> class="tc-edit-typeeditor tc-edit-texteditor tc-popup-handle" tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[type]then[true]] ~[[false]] }}} cancelPopups="yes" configTiddlerFilter="[[$:/core/ui/EditTemplate/type]]" inputCancelActions=<>/><$button popup=<> class="tc-btn-invisible tc-btn-dropdown tc-small-gap" tooltip={{$:/language/EditTemplate/Type/Dropdown/Hint}} aria-label={{$:/language/EditTemplate/Type/Dropdown/Caption}}>{{$:/core/images/down-arrow}}<$button message="tm-remove-field" param="type" class="tc-btn-invisible tc-btn-icon" tooltip={{$:/language/EditTemplate/Type/Delete/Hint}} aria-label={{$:/language/EditTemplate/Type/Delete/Caption}}>{{$:/core/images/delete-button}}<$action-deletetiddler $filter="[] [] []"/>
        diff --git a/core/ui/PageTemplate.tid b/core/ui/PageTemplate.tid index faf1a06b6..f0ab4852a 100644 --- a/core/ui/PageTemplate.tid +++ b/core/ui/PageTemplate.tid @@ -13,8 +13,7 @@ icon: $:/core/images/layout-button tv-enable-drag-and-drop={{$:/config/DragAndDrop/Enable}} tv-show-missing-links={{$:/config/MissingLinks}} storyviewTitle={{$:/view}} - languageTitle={{{ [{$:/language}get[name]] }}} - tv-text-direction={{$:/config/DefaultTextDirection}}> + languageTitle={{{ [{$:/language}get[name]] }}}>
        ] [[tc-language-]addsuffix] :and[unique[]join[ ]] }}} > diff --git a/core/ui/ViewTemplate.tid b/core/ui/ViewTemplate.tid index 3f39f3496..dcba5c953 100644 --- a/core/ui/ViewTemplate.tid +++ b/core/ui/ViewTemplate.tid @@ -7,7 +7,7 @@ $:/state/folded/$(currentTiddler)$ \define cancel-delete-tiddler-actions(message) <$action-sendmessage $message="tm-$message$-tiddler"/> \import [all[shadows+tiddlers]tag[$:/tags/Macro/View]!is[draft]] [all[shadows+tiddlers]tag[$:/tags/Global/View]!is[draft]] <$vars storyTiddler=<> tiddlerInfoState=<>> -
        > data-tiddler-title=<> data-tags={{!!tags}} class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/TiddlerTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-tiddler-frame tc-tiddler-view-frame [is[tiddler]then[tc-tiddler-exists]] [is[missing]!is[shadow]then[tc-tiddler-missing]] [is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [is[system]then[tc-tiddler-system]] [{!!class}] [tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}} role="article"> +
        > data-tags={{!!tags}} class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/TiddlerTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-tiddler-frame tc-tiddler-view-frame [is[tiddler]then[tc-tiddler-exists]] [is[missing]!is[shadow]then[tc-tiddler-missing]] [is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [is[system]then[tc-tiddler-system]] [{!!class}] [tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}} role="article"> <$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate]!is[draft]]" variable="listItem"> <$transclude tiddler=<>/> diff --git a/core/ui/ViewTemplate/body.tid b/core/ui/ViewTemplate/body.tid index 36cac1e18..34e6aaa38 100644 --- a/core/ui/ViewTemplate/body.tid +++ b/core/ui/ViewTemplate/body.tid @@ -3,7 +3,7 @@ tags: $:/tags/ViewTemplate \import [all[shadows+tiddlers]tag[$:/tags/Macro/View/Body]!is[draft]] [all[shadows+tiddlers]tag[$:/tags/Global/View/Body]!is[draft]] -<$reveal tag="div" class="tc-tiddler-body" type="nomatch" stateTitle=<> text="hide" retain="yes" animate="yes" dir=<>> +<$reveal tag="div" class="tc-tiddler-body" type="nomatch" stateTitle=<> text="hide" retain="yes" animate="yes"> <$transclude tiddler={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/ViewTemplateBodyFilter]!is[draft]get[text]] :and[!is[blank]else[$:/core/ui/ViewTemplate/body/default]] }}} /> diff --git a/core/ui/ViewTemplate/subtitle.tid b/core/ui/ViewTemplate/subtitle.tid index 611130869..a0436b095 100644 --- a/core/ui/ViewTemplate/subtitle.tid +++ b/core/ui/ViewTemplate/subtitle.tid @@ -3,7 +3,7 @@ tags: $:/tags/ViewTemplate \whitespace trim <$reveal type="nomatch" stateTitle=<> text="hide" tag="div" retain="yes" animate="yes"> -
        >> +
        <$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate/Subtitle]!has[draft.of]]" variable="subtitleTiddler" counter="indexSubtitleTiddler"> <$list filter="[match[no]]" variable="ignore">   diff --git a/core/ui/ViewTemplate/tags.tid b/core/ui/ViewTemplate/tags.tid index 95b5dbe39..d1f4e55c9 100644 --- a/core/ui/ViewTemplate/tags.tid +++ b/core/ui/ViewTemplate/tags.tid @@ -3,5 +3,5 @@ tags: $:/tags/ViewTemplate \whitespace trim <$reveal type="nomatch" stateTitle=<> text="hide" tag="div" retain="yes" animate="yes"> -
        >><$list filter="[all[current]tags[]sort[title]]" template="$:/core/ui/TagTemplate" storyview="pop"/>
        +
        <$list filter="[all[current]tags[]sort[title]]" template="$:/core/ui/TagTemplate" storyview="pop"/>
        diff --git a/core/ui/ViewTemplate/title.tid b/core/ui/ViewTemplate/title.tid index 19d375068..98695f6bf 100644 --- a/core/ui/ViewTemplate/title.tid +++ b/core/ui/ViewTemplate/title.tid @@ -6,7 +6,7 @@ tags: $:/tags/ViewTemplate fill:$(foregroundColor)$; \end
        -
        >> +
        <$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewToolbar]!has[draft.of]] :filter[lookup[$:/config/ViewToolbarButtons/Visibility/]!match[hide]]" storyview="pop" variable="listItem"><$set name="tv-config-toolbar-class" filter="[] [encodeuricomponent[]addprefix[tc-btn-]]"><$transclude tiddler=<>/> diff --git a/core/wiki/config/DefaultTextDirection.tid b/core/wiki/config/DefaultTextDirection.tid deleted file mode 100644 index 6140bbf7b..000000000 --- a/core/wiki/config/DefaultTextDirection.tid +++ /dev/null @@ -1,2 +0,0 @@ -title: $:/config/DefaultTextDirection -text: auto diff --git a/editions/tw5.com/tiddlers/Right-To-Left Languages.tid b/editions/tw5.com/tiddlers/Right-To-Left Languages.tid deleted file mode 100644 index d32d01524..000000000 --- a/editions/tw5.com/tiddlers/Right-To-Left Languages.tid +++ /dev/null @@ -1,11 +0,0 @@ -created: 20230613162508509 -modified: 20230613162508509 -title: Right-To-Left Languages -type: text/vnd.tiddlywiki - -<<.from-version "5.3.0">> The [[language plugins|Languages]] in TiddlyWiki's plugin library apply the appropriate [["right-to-left" setting|https://www.w3.org/International/questions/qa-html-dir]] to the entire document. To set the right to left setting independently for an individual tiddler, use the `\dir` [[pragma|Pragma]] at the top of the tiddler: - -``` -\dir rtl -This text will be displayed with right-to-left formatting -``` diff --git a/editions/tw5.com/tiddlers/pragmas/Pragma_ _dir.tid b/editions/tw5.com/tiddlers/pragmas/Pragma_ _dir.tid deleted file mode 100644 index bc5774e30..000000000 --- a/editions/tw5.com/tiddlers/pragmas/Pragma_ _dir.tid +++ /dev/null @@ -1,13 +0,0 @@ -created: 20230613162508509 -modified: 20230613162508509 -tags: Pragmas -title: Pragma: \dir -type: text/vnd.tiddlywiki - -<<.from-version "5.3.0">> The ''\dir'' [[pragma|Pragmas]] is used to set the text direction of text within a tiddler -- see [[Right-To-Left Languages]]. - -The ''\dir'' pragma should be used after any procedure, function, widget or macro definitions. - -* `\dir ltr` – sets text direction to left-to-right -* `\dir rtl` – sets text direction to right-to-left -* `\dir auto` – causes the browser to attempt to automatically deduce the text direction diff --git a/plugins/tiddlywiki/codemirror/engine.js b/plugins/tiddlywiki/codemirror/engine.js index e8749481d..e775e1c95 100755 --- a/plugins/tiddlywiki/codemirror/engine.js +++ b/plugins/tiddlywiki/codemirror/engine.js @@ -109,9 +109,6 @@ function CodeMirrorEngine(options) { if(this.widget.editTabIndex) { config["tabindex"] = this.widget.editTabIndex; } - if(this.widget.editDir) { - config.direction = this.widget.editDir; - } config.editWidget = this.widget; // Create the CodeMirror instance this.cm = window.CodeMirror(function(cmDomNode) { From 9b8db5dbb1baa4d94c857d30f8ed6e539eba72c3 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Thu, 22 Jun 2023 08:48:48 +0100 Subject: [PATCH 38/94] Update to Google Analytics 4 (#7554) * Adopt Google Analytics 4 tag code * Fix typo * Temporarily add Google Analytics tracking to tw5.com So that we can test everything is working with the Vercel preview * Remove test configuration --- .../googleanalytics/googleanalytics.js | 21 ++++++++++--------- plugins/tiddlywiki/googleanalytics/readme.tid | 2 +- .../tiddlywiki/googleanalytics/settings.tid | 5 ++--- plugins/tiddlywiki/googleanalytics/usage.tid | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/plugins/tiddlywiki/googleanalytics/googleanalytics.js b/plugins/tiddlywiki/googleanalytics/googleanalytics.js index 1634e465b..617a7a17a 100644 --- a/plugins/tiddlywiki/googleanalytics/googleanalytics.js +++ b/plugins/tiddlywiki/googleanalytics/googleanalytics.js @@ -17,7 +17,7 @@ exports.name = "google-analytics"; exports.platforms = ["browser"]; exports.synchronous = true; -var CONFIG_CONSENT_REQUIRED_TITLE = "$:/config/cookie-consent-required", +var CONFIG_CONSENT_REQUIRED_TITLE = "$:/config/cookie-consent-required", // "yes" or "no" (the default) CONSENT_TITLE = "$:/state/consent-banner/accepted"; // "": undeclared, "yes": accepted, "no": declined exports.startup = function() { @@ -25,15 +25,16 @@ exports.startup = function() { initialiseGoogleAnalytics = function() { console.log("Initialising Google Analytics"); hasInitialised = true; - var gaAccount = $tw.wiki.getTiddlerText("$:/GoogleAnalyticsAccount","").replace(/\n/g,""), - gaDomain = $tw.wiki.getTiddlerText("$:/GoogleAnalyticsDomain","auto").replace(/\n/g,""); - // Using ga "isogram" function - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); - ga('create',gaAccount,gaDomain); - ga('send','pageview'); + var gaMeasurementID = $tw.wiki.getTiddlerText("$:/GoogleAnalyticsMeasurementID","").replace(/\n/g,""); + var url ="https://www.googletagmanager.com/gtag/js?id=" + gaMeasurementID; + window.dataLayer = window.dataLayer || []; + window.gtag = function() { window.dataLayer?.push(arguments); }; + window.gtag("js",new Date()); + window.gtag("config",gaMeasurementID); + const scriptElement = window.document.createElement("script"); + scriptElement.async = true; + scriptElement.src = url; + window.document.head.appendChild(scriptElement); }; // Initialise now if consent isn't required if($tw.wiki.getTiddlerText(CONFIG_CONSENT_REQUIRED_TITLE) !== "yes") { diff --git a/plugins/tiddlywiki/googleanalytics/readme.tid b/plugins/tiddlywiki/googleanalytics/readme.tid index f10803be1..47504412c 100644 --- a/plugins/tiddlywiki/googleanalytics/readme.tid +++ b/plugins/tiddlywiki/googleanalytics/readme.tid @@ -1,6 +1,6 @@ title: $:/plugins/tiddlywiki/googleanalytics/readme -This plugin enables you to use Google Analytics to track access to your online TiddlyWiki document. Based upon the [[official Google code|https://developers.google.com/analytics/devguides/collection/analyticsjs]]. +This plugin enables you to use Google Analytics to track access to your online TiddlyWiki document. By default, the user is not asked for permission before initialising Google Analytics. This plugin also optionally integrates with the "Consent Banner" plugin (also found in the official plugin library) so that Google Analytics is not initialised until the user grants explicit permission. diff --git a/plugins/tiddlywiki/googleanalytics/settings.tid b/plugins/tiddlywiki/googleanalytics/settings.tid index d88fe0579..976b052c5 100644 --- a/plugins/tiddlywiki/googleanalytics/settings.tid +++ b/plugins/tiddlywiki/googleanalytics/settings.tid @@ -1,7 +1,6 @@ title: $:/plugins/tiddlywiki/googleanalytics/settings -You have only two value to set, only first is mandatory: +You have only two value to set, only the first is mandatory: -# ''[[Google Analytics Account|$:/GoogleAnalyticsAccount]]'': (mandatory) a code of the form `UA-XXXXXX-XX` where X are digits
        <$edit-text tiddler="$:/GoogleAnalyticsAccount" default="" tag="input"/> +# ''[[Google Analytics Measurement ID|$:/GoogleAnalyticsMeasurementID]]'': (mandatory) a code of the form `G-XXXXXXXXXX` where X are digits or uppercase letters
        <$edit-text tiddler="$:/GoogleAnalyticsMeasurementID" default="" tag="input"/> -# ''[[Google Analytics Domain|$:/GoogleAnalyticsDomain]]'': (optional) the website URL where the TiddlyWiki file is published. Defaults to `auto` if not set.
        <$edit-text tiddler="$:/GoogleAnalyticsDomain" default="" tag="input"/> diff --git a/plugins/tiddlywiki/googleanalytics/usage.tid b/plugins/tiddlywiki/googleanalytics/usage.tid index d6572f27d..1fbd5fc2f 100644 --- a/plugins/tiddlywiki/googleanalytics/usage.tid +++ b/plugins/tiddlywiki/googleanalytics/usage.tid @@ -7,7 +7,7 @@ If you don't already have an account: # Go to the Google Analytics website: http://www.google.com/analytics/ # Click the ''Access Google Analytics'' button and follow instructions to set up your account # Enter the URL where the wiki is hosted -# Note the Tracking ID for this domain of the form `UA-XXXXXX-XX` +# Note the Tracking ID for this domain of the form `G-XXXXXXXXXX` !! Install the plugin on your local copy of the TiddlyWiki @@ -20,5 +20,5 @@ If you don't already have an account: !! Upload the new version of your TiddlyWiki -# Upload the saved TiddlyWiki to TiddlySpot, GitHub, GitLab or other web host +# Upload the saved TiddlyWiki to Tiddlyhost, GitHub, GitLab or other web host # Return to your Google Analytics page to check that your site is being tracked From a5c258ecac14ce9c5cf2c21b40119db775bd31cb Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Sat, 24 Jun 2023 10:51:20 +0100 Subject: [PATCH 39/94] Update release note --- .../prerelease/tiddlers/Release 5.3.0.tid | 22 ++++++++++++++----- .../tiddlers/hellothere/HelloThere.tid | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/editions/prerelease/tiddlers/Release 5.3.0.tid b/editions/prerelease/tiddlers/Release 5.3.0.tid index cf1ce0098..6ddf19598 100644 --- a/editions/prerelease/tiddlers/Release 5.3.0.tid +++ b/editions/prerelease/tiddlers/Release 5.3.0.tid @@ -1,6 +1,6 @@ caption: 5.3.0 -created: 20230506164543446 -modified: 20230506164543446 +created: 20230624100932287 +modified: 20230624100932287 tags: ReleaseNotes title: Release 5.3.0 type: text/vnd.tiddlywiki @@ -30,14 +30,24 @@ These changes lay the groundwork for macros and related features to be deprecate The new transclusion architecture is not by itself sufficient to enable us to fully deprecate macros yet. To handle the remaining use cases we propose a new backtick quoted attribute format that allows for the substitution of variable values. See https://github.com/Jermolene/TiddlyWiki5/issues/6663 for details. +! HTTP Requests in WikiText + +<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7422">> new [[WidgetMessage: tm-http-request]] for performing HTTP requests in WikiText. This opens up some exciting new opportunities: + +* Integration with Web-based APIs. The documentation includes an [[example of using the Zotero API|WidgetMessage: tm-http-request Example - Zotero]] to retrieve academic citation data +* Dynamic content loading: additional tiddlers can be imported dynamically after the main wiki has loaded + ! Defaulting to Disabling CamelCase Links -<<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/7513">> CamelCase linking is now disabled by default. (Note that this wiki has CamelCase linking explicitly enabled) +<<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/7513">> CamelCase linking is now disabled by default for new wikis. (Note that this wiki has CamelCase linking explicitly enabled) ! Plugin Improvements +* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/7554">> Google Analytics plugin to use new GA4 code. Note that the update requires manual configuration to use the new "measurement ID" instead of the old "account ID" * <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7260">> Dynannotate pugin to support three additional search modes * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7365">> problem with [[BrowserStorage Plugin]] unnecessarily saving shadow tiddlers + +* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7398">> [[BrowserStorage Plugin]] to request that browser storage be persisted without eviction * <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7493">> [[CodeMirror Plugin]] to add an option to make trailing spaces visible ! Translation improvement @@ -52,7 +62,7 @@ Improvements to the following translations: ! Usability Improvements -* +* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7524">> consistency of layout of "Settings" tab in $:/ControlPanel ! Widget Improvements @@ -69,9 +79,11 @@ Improvements to the following translations: * <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7413">> [[Core Icons]] to allow the size to be controlled with a parameter ** <<.warning """This change can cause problems with non-standard usage of the core icons where the text is directly rendered instead of being transcluded""">> * <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7182">> new [[thisTiddler Variable]] that refers to the tiddler currently being rendered +* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7530">> `data-tag-title` attribute to all tag pills, allowing easier [[Custom tag pill styles]] * <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7332">> [[Story Tiddler Template Cascade]] handling to fall back to the default template if the output of the cascade is not valid * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7378">> missing file extensions for "audio/mpeg" files - +* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7417">> [[Table-of-Contents Macros]] to add consistent support for an ''exclude'' parameter +* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/commit/190613ad2989f70526f86eef17f524087f60eb72">> [[tv-config-static Variable]] for indicating static rendering ! Bug Fixes * <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7215">> importing tiddlers by pasting tiddler data diff --git a/editions/tw5.com/tiddlers/hellothere/HelloThere.tid b/editions/tw5.com/tiddlers/hellothere/HelloThere.tid index d58179819..3a2e07fdd 100644 --- a/editions/tw5.com/tiddlers/hellothere/HelloThere.tid +++ b/editions/tw5.com/tiddlers/hellothere/HelloThere.tid @@ -1,6 +1,6 @@ created: 20130822170200000 list: [[A Gentle Guide to TiddlyWiki]] [[Discover TiddlyWiki]] [[Some of the things you can do with TiddlyWiki]] [[Ten reasons to switch to TiddlyWiki]] Examples [[What happened to the original TiddlyWiki?]] -modified: 20230326083239710 +modified: 20230624100932287 tags: TableOfContents title: HelloThere type: text/vnd.tiddlywiki From e5566543c91d1c8dba15fd105aaf711d63ed893e Mon Sep 17 00:00:00 2001 From: Mario Pietsch Date: Sat, 24 Jun 2023 15:52:43 +0200 Subject: [PATCH 40/94] Make tag-macro and tag*-templates human readable for future improvements (#7559) --- core/ui/MoreSideBar/Tags.tid | 5 ++-- core/ui/TagPickerTagTemplate.tid | 43 +++++++++++++++++++------------- core/ui/TagTemplate.tid | 29 +++++++++++++-------- core/wiki/macros/tag.tid | 38 ++++++++++++++++++++++------ 4 files changed, 76 insertions(+), 39 deletions(-) diff --git a/core/ui/MoreSideBar/Tags.tid b/core/ui/MoreSideBar/Tags.tid index 0a4727bc3..b1b67bb67 100644 --- a/core/ui/MoreSideBar/Tags.tid +++ b/core/ui/MoreSideBar/Tags.tid @@ -3,15 +3,14 @@ tags: $:/tags/MoreSideBar caption: {{$:/language/SideBar/Tags/Caption}} \whitespace trim - <$let tv-config-toolbar-icons="yes" tv-config-toolbar-text="yes" tv-config-toolbar-class="">
        - {{$:/core/ui/Buttons/tag-manager}} + {{$:/core/ui/Buttons/tag-manager}}
        <$list filter={{$:/core/Filters/AllTags!!filter}}>
        - <$transclude tiddler="$:/core/ui/TagTemplate"/> + <$transclude tiddler="$:/core/ui/TagTemplate"/>

        diff --git a/core/ui/TagPickerTagTemplate.tid b/core/ui/TagPickerTagTemplate.tid index 6329f86ae..9e8689153 100644 --- a/core/ui/TagPickerTagTemplate.tid +++ b/core/ui/TagPickerTagTemplate.tid @@ -2,22 +2,29 @@ title: $:/core/ui/TagPickerTagTemplate \whitespace trim <$button class=<> tag="a" tooltip={{$:/language/EditTemplate/Tags/Add/Button/Hint}}> -<$list filter="[minlength[1]]"> -<$action-listops $tiddler=<> $field=<> $subfilter="[]"/> - -<$set name="currentTiddlerCSSEscaped" value={{{ [escapecss[]] }}}> -<$action-sendmessage $message="tm-focus-selector" $param=<> preventScroll="true"/> - -<> -<$list filter="[minlength[1]]"> -<$action-setfield $tiddler=<> text="yes"/> - -<> -<$set name="backgroundColor" value={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}}> -<$wikify name="foregroundColor" text="""<$macrocall $name="contrastcolour" target=<> fallbackTarget=<> colourA=<> colourB=<>/>"""> -> data-tag-title=<> > -{{||$:/core/ui/TiddlerIcon}}<$view field="title" format="text"/> - - - + <$list filter="[minlength[1]]"> + <$action-listops $tiddler=<> $field=<> $subfilter="[]"/> + + <$set name="currentTiddlerCSSEscaped" value={{{ [escapecss[]] }}}> + <$action-sendmessage $message="tm-focus-selector" $param=<> preventScroll="true"/> + + <> + <$list filter="[minlength[1]]"> + <$action-setfield $tiddler=<> text="yes"/> + + <> + <$set name="backgroundColor" + value={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} + > + <$wikify name="foregroundColor" + text="""<$macrocall $name="contrastcolour" target=<> fallbackTarget=<> colourA=<> colourB=<>/>""" + > + > + data-tag-title=<> + > + {{||$:/core/ui/TiddlerIcon}}<$view field="title" format="text"/> + + + diff --git a/core/ui/TagTemplate.tid b/core/ui/TagTemplate.tid index f137f22a0..49e836671 100644 --- a/core/ui/TagTemplate.tid +++ b/core/ui/TagTemplate.tid @@ -3,16 +3,23 @@ title: $:/core/ui/TagTemplate \whitespace trim >> <$set name="transclusion" value=<>> -<$macrocall $name="tag-pill-body" tag=<> icon={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} colour={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} palette={{$:/palette}} element-tag="""$button""" element-attributes="""popup=<> dragFilter='[all[current]tagging[]]' tag='span'"""/> -<$reveal state=<> type="popup" position="below" animate="yes" class="tc-drop-down"> -<$set name="tv-show-missing-links" value="yes"> -<$transclude tiddler="$:/core/ui/ListItemTemplate"/> - -<$list filter="[all[shadows+tiddlers]tag[$:/tags/TagDropdown]!has[draft.of]]" variable="listItem"> -<$transclude tiddler=<>/> - -
        -<$macrocall $name="list-tagged-draggable" tag=<>/> - + <$macrocall $name="tag-pill-body" + tag=<> + icon={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} + colour={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} + palette={{$:/palette}} + element-tag="$button" + element-attributes="""popup=<> dragFilter="[all[current]tagging[]]" tag='span'""" + /> + <$reveal state=<> type="popup" position="below" animate="yes" class="tc-drop-down"> + <$set name="tv-show-missing-links" value="yes"> + <$transclude tiddler="$:/core/ui/ListItemTemplate"/> + + <$list filter="[all[shadows+tiddlers]tag[$:/tags/TagDropdown]!has[draft.of]]" variable="listItem"> + <$transclude tiddler=<>/> + +
        + <$macrocall $name="list-tagged-draggable" tag=<>/> +
        diff --git a/core/wiki/macros/tag.tid b/core/wiki/macros/tag.tid index 3616fb97d..03dd8cb98 100644 --- a/core/wiki/macros/tag.tid +++ b/core/wiki/macros/tag.tid @@ -9,26 +9,50 @@ color:$(foregroundColor)$; \define tag-pill-inner(tag,icon,colour,fallbackTarget,colourA,colourB,element-tag,element-attributes,actions) +\whitespace trim <$vars foregroundColor=<> - backgroundColor="""$colour$""" -><$element-tag$ + backgroundColor=<<__colour__>> +> +<$element-tag$ $element-attributes$ class="tc-tag-label tc-btn-invisible" style=<> ->$actions$<$transclude tiddler="""$icon$"""/><$view tiddler=<<__tag__>> field="title" format="text" /> +> + <<__actions__>> + <$transclude tiddler=<<__icon__>>/> + <$view tiddler=<<__tag__>> field="title" format="text" /> + \end \define tag-pill-body(tag,icon,colour,palette,element-tag,element-attributes,actions) -<$macrocall $name="tag-pill-inner" tag=<<__tag__>> icon="""$icon$""" colour="""$colour$""" fallbackTarget={{$palette$##tag-background}} colourA={{$palette$##foreground}} colourB={{$palette$##background}} element-tag="""$element-tag$""" element-attributes="""$element-attributes$""" actions="""$actions$"""/> +\whitespace trim +<$macrocall $name="tag-pill-inner" + tag=<<__tag__>> + icon=<<__icon__>> + colour=<<__colour__>> + fallbackTarget={{$palette$##tag-background}} + colourA={{$palette$##foreground}} + colourB={{$palette$##background}} + element-tag=<<__element-tag__>> + element-attributes=<<__element-attributes__>> + actions=<<__actions__>> +/> \end \define tag-pill(tag,element-tag:"span",element-attributes:"",actions:"") \whitespace trim >> -<$let currentTiddler=<<__tag__>>> -<$macrocall $name="tag-pill-body" tag=<<__tag__>> icon={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} colour={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} palette={{$:/palette}} element-tag="""$element-tag$""" element-attributes="""$element-attributes$""" actions="""$actions$"""/> - + <$let currentTiddler=<<__tag__>>> + <$macrocall $name="tag-pill-body" + tag=<<__tag__>> + icon={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} + colour={{{ [] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} + palette={{$:/palette}} + element-tag=<<__element-tag__>> + element-attributes=<<__element-attributes__>> + actions=<<__actions__>>/> + \end From 3825e2579fb273d014e04c82a4ed8280c94a2e2e Mon Sep 17 00:00:00 2001 From: Saq Imtiaz Date: Sat, 24 Jun 2023 15:57:15 +0200 Subject: [PATCH 41/94] Adds Text substitution support in widget attributes and new operator (#7526) * feat: new text substitution support, first pass * fix: use the widget method instead of evaluating a filter * revert to earlier implementation that emulates macro syntax * fix: capitalize comments * feat: add support for triple backticks for substituted attributes * docs: added docs for substitute operator * chore: more docs tweaks * docs: substituted attributes, refactored docs for widget attributes * docs: fixed typo * docs: more examples for substituted attributes * docs: updated prior documentation on concatenating text and variables * docs: documentation corrections * Update editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid Co-authored-by: btheado --------- Co-authored-by: btheado --- core/modules/filters/substitute.js | 36 ++++++++++ core/modules/parsers/parseutils.js | 18 +++-- core/modules/widgets/widget.js | 2 + core/modules/wiki.js | 28 ++++++++ .../tests/data/filters/substitute.tid | 40 +++++++++++ .../data/widgets/SubstitutedAttributes.tid | 19 ++++++ .../test/tiddlers/tests/test-html-parser.js | 10 +++ .../substitute Operator (Examples).tid | 37 ++++++++++ .../tiddlers/filters/substitute Operator.tid | 27 ++++++++ ...and variables using macro substitution.tid | 3 +- .../wikitext/Filtered Attribute Values.tid | 16 +++++ .../tiddlers/wikitext/HTML in WikiText.tid | 67 ++----------------- .../wikitext/Literal Attribute Values.tid | 30 +++++++++ .../wikitext/Substituted Attribute Values.tid | 45 +++++++++++++ .../wikitext/Transcluded Attribute Values.tid | 14 ++++ .../wikitext/Variable Attribute Values.tid | 14 ++++ .../tiddlers/wikitext/Widget Attributes.tid | 21 ++++++ 17 files changed, 361 insertions(+), 66 deletions(-) create mode 100644 core/modules/filters/substitute.js create mode 100644 editions/test/tiddlers/tests/data/filters/substitute.tid create mode 100644 editions/test/tiddlers/tests/data/widgets/SubstitutedAttributes.tid create mode 100644 editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid create mode 100644 editions/tw5.com/tiddlers/filters/substitute Operator.tid create mode 100644 editions/tw5.com/tiddlers/wikitext/Filtered Attribute Values.tid create mode 100644 editions/tw5.com/tiddlers/wikitext/Literal Attribute Values.tid create mode 100644 editions/tw5.com/tiddlers/wikitext/Substituted Attribute Values.tid create mode 100644 editions/tw5.com/tiddlers/wikitext/Transcluded Attribute Values.tid create mode 100644 editions/tw5.com/tiddlers/wikitext/Variable Attribute Values.tid create mode 100644 editions/tw5.com/tiddlers/wikitext/Widget Attributes.tid diff --git a/core/modules/filters/substitute.js b/core/modules/filters/substitute.js new file mode 100644 index 000000000..655ef7321 --- /dev/null +++ b/core/modules/filters/substitute.js @@ -0,0 +1,36 @@ +/*\ +title: $:/core/modules/filters/substitute.js +type: application/javascript +module-type: filteroperator + +Filter operator for substituting variables and embedded filter expressions with their corresponding values + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +/* +Export our filter function +*/ +exports.substitute = function(source,operator,options) { + var results = [], + operands = []; + $tw.utils.each(operator.operands,function(operand,index){ + operands.push({ + name: (index + 1).toString(), + value: operand + }); + }); + source(function(tiddler,title) { + if(title) { + results.push(options.wiki.getSubstitutedText(title,options.widget,{substitutions:operands})); + } + }); + return results; +}; + +})(); + \ No newline at end of file diff --git a/core/modules/parsers/parseutils.js b/core/modules/parsers/parseutils.js index 6a0902c6f..1f86dd909 100644 --- a/core/modules/parsers/parseutils.js +++ b/core/modules/parsers/parseutils.js @@ -305,10 +305,11 @@ exports.parseAttribute = function(source,pos) { start: pos }; // Define our regexps - var reAttributeName = /([^\/\s>"'=]+)/g, - reUnquotedAttribute = /([^\/\s<>"'=]+)/g, + var reAttributeName = /([^\/\s>"'`=]+)/g, + reUnquotedAttribute = /([^\/\s<>"'`=]+)/g, reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g, - reIndirectValue = /\{\{([^\}]+)\}\}/g; + reIndirectValue = /\{\{([^\}]+)\}\}/g, + reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g; // Skip whitespace pos = $tw.utils.skipWhiteSpace(source,pos); // Get the attribute name @@ -361,8 +362,15 @@ exports.parseAttribute = function(source,pos) { node.type = "macro"; node.value = macroInvocation; } else { - node.type = "string"; - node.value = "true"; + var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue); + if(substitutedValue) { + pos = substitutedValue.end; + node.type = "substituted"; + node.rawValue = substitutedValue.match[1] || substitutedValue.match[2]; + } else { + node.type = "string"; + node.value = "true"; + } } } } diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index 8ffee0ab7..3780c05cf 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -380,6 +380,8 @@ Widget.prototype.computeAttribute = function(attribute) { } else if(attribute.type === "macro") { var variableInfo = this.getVariableInfo(attribute.value.name,{params: attribute.value.params}); value = variableInfo.text; + } else if(attribute.type === "substituted") { + value = this.wiki.getSubstitutedText(attribute.rawValue,this) || ""; } else { // String attribute value = attribute.value; } diff --git a/core/modules/wiki.js b/core/modules/wiki.js index ca31da8d2..93e818f21 100755 --- a/core/modules/wiki.js +++ b/core/modules/wiki.js @@ -1063,6 +1063,34 @@ exports.getTextReferenceParserInfo = function(title,field,index,options) { return parserInfo; } +/* +Parse a block of text of a specified MIME type + text: text on which to perform substitutions + widget + options: see below +Options include: + substitutions: an optional array of substitutions +*/ +exports.getSubstitutedText = function(text,widget,options) { + options = options || {}; + text = text || ""; + var self = this, + substitutions = options.substitutions || [], + output; + // Evaluate embedded filters and substitute with first result + output = text.replace(/\$\{([\S\s]+?)\}\$/g, function(match,filter) { + return self.filterTiddlers(filter,widget)[0] || ""; + }); + // Process any substitutions provided in options + $tw.utils.each(substitutions,function(substitute) { + 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 widget.getVariable(varname,{defaultValue: ""}) + }); +}; + /* Make a widget tree for a parse tree parser: parser object diff --git a/editions/test/tiddlers/tests/data/filters/substitute.tid b/editions/test/tiddlers/tests/data/filters/substitute.tid new file mode 100644 index 000000000..873d8e0ba --- /dev/null +++ b/editions/test/tiddlers/tests/data/filters/substitute.tid @@ -0,0 +1,40 @@ +title: Filters/substitute +description: Test substitute operator +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: substitute filter data 1 +tags: Hello There [[Welcome to TiddlyWiki]] GettingStarted + +TiddlyWiki ++ +title: substitute filter data 2 + +The output of the filter `[[substitute filter data 1]tags[]]` is ${[[substitute filter data 1]tags[]]}$. ++ +title: substitute filter data 3 + +Welcome to $(projectname)$ $1$ $2$ $3$. Tiddlers starting with `substitute`: ${[prefix[substitute]format:titlelist[]join[ ]]}$. ++ +title: Output + +\whitespace trim +<$let projectname="TiddlyWiki"> +(<$text text={{{ [[]substitute[]] }}}/>) +(<$text text={{{ [[Hello There, welcome to $TiddlyWiki$]substitute[]] }}}/>) +(<$text text={{{ [[Welcome to $(projectname)$]substitute[]] }}}/>) +(<$text text={{{ [[Welcome to $(projectname)$ $1$]substitute[today]] }}}/>) +(<$text text={{{ [[This is not a valid embedded filter ${ hello )$]substitute[]] }}}/>) +(<$text text={{{ [{substitute filter data 2}substitute[]] }}}/>) +(<$text text={{{ [{substitute filter data 3}substitute[every],[day]] }}}/>) + ++ +title: ExpectedResult + +

        () +(Hello There, welcome to $TiddlyWiki$) +(Welcome to TiddlyWiki) +(Welcome to TiddlyWiki today) +(This is not a valid embedded filter ${ hello )$) +(The output of the filter `[[substitute filter data 1]tags[]]` is Hello.) +(Welcome to TiddlyWiki every day $3$. Tiddlers starting with `substitute`: [[substitute filter data 1]] [[substitute filter data 2]] [[substitute filter data 3]].)

        \ 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 new file mode 100644 index 000000000..408d202c6 --- /dev/null +++ b/editions/test/tiddlers/tests/data/widgets/SubstitutedAttributes.tid @@ -0,0 +1,19 @@ +title: Widgets/SubstitutedAttributes +description: Attributes specified as string that should have substitution performed. +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +\whitespace trim +<$let project="TiddlyWiki" disabled="true"> +
        +
        + + ++ +title: ExpectedResult + +

        \ No newline at end of file diff --git a/editions/test/tiddlers/tests/test-html-parser.js b/editions/test/tiddlers/tests/test-html-parser.js index cdc8dee47..d2266ca5e 100644 --- a/editions/test/tiddlers/tests/test-html-parser.js +++ b/editions/test/tiddlers/tests/test-html-parser.js @@ -161,6 +161,16 @@ describe("HTML tag new parser tests", function() { expect($tw.utils.parseAttribute(" attrib1>",0)).toEqual( { type : 'string', value : 'true', start : 0, name : 'attrib1', end : 8 } ); + expect($tw.utils.parseAttribute("p=`blah` ",1)).toEqual(null); + expect($tw.utils.parseAttribute("p=`blah` ",0)).toEqual( + { start: 0, name: 'p', type: 'substituted', rawValue: 'blah', end: 8 } + ); + expect($tw.utils.parseAttribute("p=```blah``` ",0)).toEqual( + { start: 0, name: 'p', type: 'substituted', rawValue: 'blah', end: 12 } + ); + expect($tw.utils.parseAttribute("p=`Hello \"There\"`",0)).toEqual( + { start: 0, name: 'p', type: 'substituted', rawValue: 'Hello "There"', end: 17 } + ); }); it("should parse HTML tags", function() { diff --git a/editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid b/editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid new file mode 100644 index 000000000..45a25e3e0 --- /dev/null +++ b/editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid @@ -0,0 +1,37 @@ +created: 20230614225302905 +modified: 20230614233448662 +tags: [[Operator Examples]] [[substitute Operator]] +title: substitute Operator (Examples) +type: text/vnd.tiddlywiki + +\define time() morning +\define field() modified +\procedure sentence() This tiddler was last $(field)$ on ${[{!!modified}format:date[DDth MMM YYYY]]}$ +\define name() Bugs Bunny +\define address() Rabbit Hole Hill + +!Substitute <<.op substitute[]>> operator parameters +<<.operator-example 1 "[[Hi, I'm $1$ and I live in $2$]substitute[Bugs Bunny],[Rabbit Hole Hill]]">> + +!Substitute variables +This example uses the following variables: + +* name: <$codeblock code=<>/> +* address: <$codeblock code=<
        >/> + +<<.inline-operator-example "[[Hi, I'm $(name)$ and I live in $(address)$]substitute[]]">> + +!Substitute variables and operator parameters +This example uses the following variable: + +* time: <$codeblock code=<
        """ + else=""/> +\end + +<$list filter="[all[current]has[from-version]]" variable="listItem"> + <$macrocall $name=".from-version" version={{!!from-version}}/> + +<$let op-head="" op-body="" op-name=""> +
        $(op-head)$<<.op-place>>$(op-body)$
        + + <$let op-head="purpose" op-body={{!!rp-purpose}}> + <<.op-row>> + + + <$let op-head="[[input|Filter Expression]]" op-body={{!!rp-input}}> + <<.op-row>> + + + <$let op-head="suffix" op-body={{!!rp-suffix}} op-name={{!!rp-suffix-name}}> + <<.op-row>> + + + <$let op-head="output" op-body={{!!rp-output}}> + <<.op-row>> + +
        + + +<$railroad text=""" +\start none +\end none +":then" +[[run|"Filter Run"]] +"""/> + +!Introduction + +The <<.op :then>> filter run prefix is used to replace the result of all previous filter runs with its output. + +If the result of all previous runs is an empty list, the <<.op :then>> prefixed filter run is not evaluated. + +If the output of a <<.op :then>> prefixed filter run is itself an empty list, the result of all previous filter runs is passed through unaltered. + +<<.tip "Note that a list with a single empty string item is not an empty list.">> + + +!! <<.op :then>> run prefix versus the <<.olink then>> operator + +The major difference between the <<.op then>> operator and a <<.op :then>> prefixed filter run is that the operator will replace //each item// of the input [[Title List]] with its parameter while <<.op :then>> will replace the //whole input list// with the result of its run. + +|doc-op-comparison tc-center|k +| !<<.op :then>> Filter Run Prefix | !<<.op then>> Operator | +|^<<.operator-example m1-1 "[tag[WikiText]] :then[[true]]">>|^<<.operator-example m1-2 "[tag[WikiText]then[true]]">>

        To make them equivalent, additional filter steps may be added:

        <<.operator-example m1-3 "[tag[WikiText]count[]compare:number:gt[0]then[true]]">>| + + +! [[Examples|Then Filter Run Prefix (Examples)]] + diff --git a/editions/tw5.com/tiddlers/filters/then Operator.tid b/editions/tw5.com/tiddlers/filters/then Operator.tid index e4ea5901e..e4d389a29 100644 --- a/editions/tw5.com/tiddlers/filters/then Operator.tid +++ b/editions/tw5.com/tiddlers/filters/then Operator.tid @@ -1,6 +1,6 @@ caption: then created: 20190802112756430 -modified: 20190802113849579 +modified: 20230501174334627 op-input: a [[selection of titles|Title Selection]] op-output: the input titles with each one replaced by the string <<.place T>> op-parameter: a string @@ -12,4 +12,6 @@ type: text/vnd.tiddlywiki <<.from-version "5.1.20">> See [[Conditional Operators]] for an overview. +<<.tip "The [[Then Filter Run Prefix]] has a similar purpose to the <<.op then>> operator. See its documentation for a comparison of usage.">> + <<.operator-examples "then">> diff --git a/editions/tw5.com/tiddlers/system/doc-styles.tid b/editions/tw5.com/tiddlers/system/doc-styles.tid index e406abb95..9ae22868f 100644 --- a/editions/tw5.com/tiddlers/system/doc-styles.tid +++ b/editions/tw5.com/tiddlers/system/doc-styles.tid @@ -285,6 +285,14 @@ ol.doc-github-contributors li { overflow: hidden; text-overflow: ellipsis; } +.doc-op-comparison { + table-layout: fixed; + width: 80%; +} +.doc-op-comparison th .doc-operator { + background-color: unset; + color: #666; +} .doc-tabs.tc-tab-buttons button { font-size: 1rem; padding: 0.5em; @@ -295,4 +303,4 @@ ol.doc-github-contributors li { } .doc-tab-link .doc-attr { color: unset; -} \ No newline at end of file +} From d46aa4ba4d847ec0231692ca6f00936937122215 Mon Sep 17 00:00:00 2001 From: "jeremy@jermolene.com" Date: Sat, 24 Jun 2023 19:04:16 +0100 Subject: [PATCH 46/94] Release note update --- editions/prerelease/tiddlers/Release 5.3.0.tid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editions/prerelease/tiddlers/Release 5.3.0.tid b/editions/prerelease/tiddlers/Release 5.3.0.tid index c9091c121..a92cb7b5a 100644 --- a/editions/prerelease/tiddlers/Release 5.3.0.tid +++ b/editions/prerelease/tiddlers/Release 5.3.0.tid @@ -83,7 +83,7 @@ Improvements to the following translations: * <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7511"> new [[deserialize Operator]] for converting various textual representations of tiddlers into JSON data * <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7292">> [[format Operator]] to support converting Unix timestamps to TiddlyWiki's native date format - +* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7392">> new [[':then' filter run prefix|Then Filter Run Prefix]] ! Hackability Improvements From bc07fd731cf3e21656eef4111e5d75cc0c9cefd0 Mon Sep 17 00:00:00 2001 From: btheado Date: Sun, 25 Jun 2023 02:14:12 -0500 Subject: [PATCH 47/94] Use .operator-example for all substitute operator examples (#7561) --- .../filters/examples/substitute Operator (Examples).tid | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid b/editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid index 45a25e3e0..ece8aecf6 100644 --- a/editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid +++ b/editions/tw5.com/tiddlers/filters/examples/substitute Operator (Examples).tid @@ -19,14 +19,14 @@ This example uses the following variables: * name: <$codeblock code=<>/> * address: <$codeblock code=<
        >/> -<<.inline-operator-example "[[Hi, I'm $(name)$ and I live in $(address)$]substitute[]]">> +<<.operator-example 2 "[[Hi, I'm $(name)$ and I live in $(address)$]substitute[]]">> !Substitute variables and operator parameters This example uses the following variable: * time: <$codeblock code=<