From 40b353bd0e7ed5a2f8103277f4600726b8ea317a Mon Sep 17 00:00:00 2001 From: Simon Huber Date: Tue, 11 Aug 2026 10:50:55 +0200 Subject: [PATCH 1/6] Touch a temp tiddler when removing a tag (#9889) * Touch a temp tiddler when removing a tag Like that removing a tag doesn't make TiddlyWiki5 wait for the Typing timeout to remove it but removes it instantly, because also a non-draft Tiddler has changed * Add release notes for bugfix in Edit Mode tags Fixes an issue where tags of Tiddlers in Edit Mode don't animate instantly when they get removed. * Add inline comment * Update release version to 5.5.0 in changenote --- core/ui/EditTemplate/tags.tid | 10 ++++++---- editions/tw5.com/tiddlers/releasenotes/5.5.0/#9889.tid | 10 ++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 editions/tw5.com/tiddlers/releasenotes/5.5.0/#9889.tid diff --git a/core/ui/EditTemplate/tags.tid b/core/ui/EditTemplate/tags.tid index 20e1cad8e5..5c29f52842 100644 --- a/core/ui/EditTemplate/tags.tid +++ b/core/ui/EditTemplate/tags.tid @@ -18,10 +18,12 @@ tags: $:/tags/EditTemplate <$button class="tc-btn-invisible tc-remove-tag-button" style.fill=<> > - <$action-listops $tiddler=<> $field=<> $subfilter="-[{!!title}]"/> - {{$:/core/images/close-button}} - - + <$action-listops $tiddler=<> $field=<> $subfilter="-[{!!title}]"/> + + <$action-setfield $tiddler="$:/temp/tags-edit-refresh" text=<>/> + {{$:/core/images/close-button}} + + \end diff --git a/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9889.tid b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9889.tid new file mode 100644 index 0000000000..9bd2612619 --- /dev/null +++ b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9889.tid @@ -0,0 +1,10 @@ +title: $:/changenotes/5.4.1/#9889 +description: Make tags in Edit Mode animate instantly when removing +tags: $:/tags/ChangeNote +release: 5.5.0 +change-type: bugfix +change-category: usability +github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9889 +github-contributors: BurningTreeC + +Fixes an issue where tags of Tiddlers in Edit Mode don't animate instantly when they get removed From aac08a6252f684e164eed0ed7a5a3d3e374b7ab7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 15:19:57 +0200 Subject: [PATCH 2/6] Bump js-yaml from 4.3.0 to 4.3.1 (#9966) Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.3.0 to 4.3.1. - [Changelog](https://github.com/nodeca/js-yaml/blob/4.3.1/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/4.3.0...4.3.1) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 4.3.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 70b62e841a..3c15a7a271 100644 --- a/package-lock.json +++ b/package-lock.json @@ -719,9 +719,9 @@ "license": "ISC" }, "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "dev": true, "funding": [ { From b40b6de3aeac4959774b5acd2d31dcb37299a695 Mon Sep 17 00:00:00 2001 From: Mario Pietsch Date: Thu, 13 Aug 2026 12:18:38 +0200 Subject: [PATCH 3/6] Make sort order using sortby more consistent (#9747) * make sort order more consistent * Fix tests, as they are to be different due to the change. * Add ChangeNote * sortby: add "end" operand to place unlisted last Give the sortby filter operator an optional second operand `end` that places input titles missing from the reference list after the listed ones, while the default still keeps them at the start. * x-listops: read a second operand; `end` sorts unlisted titles to the end of the list, the default (no operand) leaves them at the start * Document the optional `place` parameter on the sortby operator and rename the operator and examples tiddlers to match their titles * Add a `sortby[...],[end]` example to the operator examples * Replace the 5.5.0 change note with one describing the new `end` operand and its unchanged default * Extend the sortby tests to cover both default (unlisted first) and `end` (unlisted last) placement * Make the sortby end flag a suffix Specify the placement of unlisted titles with an operator suffix. Eg: `sortby:end[a b c]` * Read the flag from `operator.suffix` * Move the example and the change note to the suffix syntax * Switch the sortby tests to the suffix syntax * Cover the sortby guard and unlisted ordering Close gaps found by mutating the sortby operator * Sort two titles to catch an off-by-one in the length guard * Keep unlisted titles in input order under the `end` suffix to catch a comparator tie break * Return a single title untouched, exercising the early return --- core/modules/filters/x-listops.js | 10 ++++++++-- editions/test/tiddlers/tests/test-filters.js | 12 +++++++++++- .../{sortby.tid => sortby Operator (Examples).tid} | 1 + .../filters/{sortby.tid => sortby Operator.tid} | 5 +++-- .../5.5.0/#9747-sortby-unlisted-placement.tid | 12 ++++++++++++ 5 files changed, 35 insertions(+), 5 deletions(-) rename editions/tw5.com/tiddlers/filters/examples/{sortby.tid => sortby Operator (Examples).tid} (83%) rename editions/tw5.com/tiddlers/filters/{sortby.tid => sortby Operator.tid} (58%) create mode 100644 editions/tw5.com/tiddlers/releasenotes/5.5.0/#9747-sortby-unlisted-placement.tid diff --git a/core/modules/filters/x-listops.js b/core/modules/filters/x-listops.js index 97eb830043..d613c2430f 100644 --- a/core/modules/filters/x-listops.js +++ b/core/modules/filters/x-listops.js @@ -160,8 +160,14 @@ exports.sortby = function(source,operator) { if(!results || results.length < 2) { return results; } - const lookup = $tw.utils.parseStringArray(operator.operand,"true"); - return results.sort((a,b) => lookup.indexOf(a) - lookup.indexOf(b)); + const lookup = $tw.utils.parseStringArray(operator.operand,"true"), + // The "end" suffix places unlisted titles last, the default is first + unlisted = operator.suffix === "end" ? lookup.length : -1, + position = (title) => { + const index = lookup.indexOf(title); + return index === -1 ? unlisted : index; + }; + return results.sort((a,b) => position(a) - position(b)); }; diff --git a/editions/test/tiddlers/tests/test-filters.js b/editions/test/tiddlers/tests/test-filters.js index 9834090c78..54d08e8dd3 100644 --- a/editions/test/tiddlers/tests/test-filters.js +++ b/editions/test/tiddlers/tests/test-filters.js @@ -940,10 +940,20 @@ describe("Filter tests", function() { it("should handle the sortby operator", function() { expect(wiki.filterTiddlers("a b c +[sortby[d e]]").join(",")).toBe("a,b,c"); expect(wiki.filterTiddlers("a b c +[sortby[b c a]]").join(",")).toBe("b,c,a"); + // By default titles missing from the reference list sort to the start expect(wiki.filterTiddlers("aa a b c +[sortby[b c a cc]]").join(",")).toBe("aa,b,c,a"); expect(wiki.filterTiddlers("a bb b c +[sortby[b c a cc]]").join(",")).toBe("bb,b,c,a"); expect(wiki.filterTiddlers("a bb cc b c +[sortby[b c a cc]]").join(",")).toBe("bb,b,c,a,cc"); - + // The "end" suffix places missing titles after the listed ones + expect(wiki.filterTiddlers("aa a b c +[sortby:end[b c a cc]]").join(",")).toBe("b,c,a,aa"); + expect(wiki.filterTiddlers("a bb b c +[sortby:end[b c a cc]]").join(",")).toBe("b,c,a,bb"); + expect(wiki.filterTiddlers("a bb cc b c +[sortby:end[b c a cc]]").join(",")).toBe("b,c,a,cc,bb"); + // Missing titles keep their input order. Avoid a repeated title here, it would be moved to the end of the input + expect(wiki.filterTiddlers("zz a yy b +[sortby:end[b a]]").join(",")).toBe("b,a,zz,yy"); + // Two titles are the shortest input that is sorted rather than returned untouched + expect(wiki.filterTiddlers("a b +[sortby[b a]]").join(",")).toBe("b,a"); + expect(wiki.filterTiddlers("a +[sortby:end[b a]]").join(",")).toBe("a"); + expect(wiki.filterTiddlers("b a b c +[sortby[]]").join(",")).toBe("a,b,c"); expect(wiki.filterTiddlers("b a b c +[sortby[a b b c]]").join(",")).toBe("a,b,c"); expect(wiki.filterTiddlers("b a b c +[sortby[b a c b]]").join(",")).toBe("b,a,c"); diff --git a/editions/tw5.com/tiddlers/filters/examples/sortby.tid b/editions/tw5.com/tiddlers/filters/examples/sortby Operator (Examples).tid similarity index 83% rename from editions/tw5.com/tiddlers/filters/examples/sortby.tid rename to editions/tw5.com/tiddlers/filters/examples/sortby Operator (Examples).tid index 83b94a3c98..12cc155bc0 100644 --- a/editions/tw5.com/tiddlers/filters/examples/sortby.tid +++ b/editions/tw5.com/tiddlers/filters/examples/sortby Operator (Examples).tid @@ -9,3 +9,4 @@ type: text/vnd.tiddlywiki <<.operator-example 1 "10 6 4 9 3 2 8 +[sortby[1 2 3 4 5 6 7 8 9 10]]">> <<.operator-example 2 "Friday Tuesday Monday Thursday Sunday +[sortby{Days of the Week!!list}]">> <<.operator-example 3 "1 Mon 5 Fri 4 Tue Sun 2 +[sortby{Days of the Week!!short}]">> +<<.operator-example 4 "1 Mon 5 Fri 4 Tue Sun 2 +[sortby:end{Days of the Week!!short}]">> diff --git a/editions/tw5.com/tiddlers/filters/sortby.tid b/editions/tw5.com/tiddlers/filters/sortby Operator.tid similarity index 58% rename from editions/tw5.com/tiddlers/filters/sortby.tid rename to editions/tw5.com/tiddlers/filters/sortby Operator.tid index 773c6a5981..0e5e036070 100644 --- a/editions/tw5.com/tiddlers/filters/sortby.tid +++ b/editions/tw5.com/tiddlers/filters/sortby Operator.tid @@ -1,11 +1,12 @@ caption: sortby created: 20151017145021839 -modified: 20151108052142057 +modified: 20260811120000000 op-input: a list of items -op-output: all items sorted by lookup list +op-output: all items sorted by the order list, with unlisted items placed first, or last with the `end` suffix op-parameter: a list specifying the order in which to sort the current list op-parameter-name: order op-purpose: sort the current list in the order of the list referenced in the parameter +op-suffix: <<.from-version "5.5.0">> optional: `end` to place items missing from <<.place order>> after the listed ones. If omitted they are placed first tags: [[Filter Operators]] [[Order Operators]] [[Listops Operators]] title: sortby Operator type: text/vnd.tiddlywiki diff --git a/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9747-sortby-unlisted-placement.tid b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9747-sortby-unlisted-placement.tid new file mode 100644 index 0000000000..fe80514061 --- /dev/null +++ b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9747-sortby-unlisted-placement.tid @@ -0,0 +1,12 @@ +change-category: filters +change-type: enhancement +created: 20260711015656000 +description: sortby accepts an optional end suffix to place titles missing from the reference list after the listed ones +github-contributors: pmario +github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9747 +release: 5.5.0 +tags: $:/tags/ChangeNote +title: $:/changenotes/5.5.0/#9747 +type: text/vnd.tiddlywiki + +* The [[sortby|sortby Operator]] filter operator now accepts an optional `end` suffix that places input titles missing from the reference list after the listed ones. The default is unchanged, so with a list `Alpha Beta Gamma` the input `Delta Epsilon Alpha Beta Gamma` still sorts to `Delta Epsilon Alpha Beta Gamma`, while `sortby:end[...]` sorts it to `Alpha Beta Gamma Delta Epsilon` (addresses [[Issue #8342|https://github.com/TiddlyWiki/TiddlyWiki5/issues/8342]]) From 0c60e1fa7a4dbef45907de0da4289b6a047b388f Mon Sep 17 00:00:00 2001 From: Simon Huber Date: Thu, 13 Aug 2026 12:21:20 +0200 Subject: [PATCH 4/6] Add class assignment to DOM node in editors (#9965) * Add class assignment to DOM node in editor * Fix indentation in assignDomNodeClasses method * Fix conditional check for changedAttributes class * Improve class assignment in EditTextWidget Refactor class assignment logic to avoid duplicates and handle whitespace. * Refactor DOM class assignment in EditTextWidget * Refactor updateDomNodeClasses for clarity and efficiency * Add changenote for enhancement in editor refresh behavior --- core/modules/editor/factory.js | 28 ++++++++++++++++++- .../tiddlers/releasenotes/5.5.0/#9965.tid | 14 ++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 editions/tw5.com/tiddlers/releasenotes/5.5.0/#9965.tid diff --git a/core/modules/editor/factory.js b/core/modules/editor/factory.js index 7d186e1248..b500fc9247 100644 --- a/core/modules/editor/factory.js +++ b/core/modules/editor/factory.js @@ -210,6 +210,29 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) { this.editShowToolbar = this.wiki.getTiddlerText(ENABLE_TOOLBAR_TITLE,"yes"); this.editShowToolbar = (this.editShowToolbar === "yes") && !!(this.children && this.children.length > 0) && (!this.document.isTiddlyWikiFakeDom); }; + + EditTextWidget.prototype.updateDomNodeClasses = function() { + var domNodeClasses = this.engine.domNode.className.split(/\s+/).filter(Boolean), + oldClasses = this.editClass.split(/\s+/).filter(Boolean), + newClasses; + + this.editClass = this.getAttribute("class",""); + newClasses = this.editClass.split(/\s+/).filter(Boolean); + + // Remove classes assigned from the old value of the class attribute + domNodeClasses = domNodeClasses.filter(function(className) { + return !oldClasses.includes(className); + }); + + // Add new classes from the updated class attribute + domNodeClasses = domNodeClasses.concat( + newClasses.filter(function(className) { + return !domNodeClasses.includes(className); + }) + ); + + this.engine.domNode.className = domNodeClasses.join(" "); + }; /* Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering @@ -217,7 +240,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.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]) { @@ -226,6 +249,9 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) { var editInfo = this.getEditInfo(); this.updateEditor(editInfo.value,editInfo.type); } + if(changedAttributes["class"]) { + this.updateDomNodeClasses(); + } this.engine.fixHeight(); if(this.editShowToolbar) { return this.refreshChildren(changedTiddlers); diff --git a/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9965.tid b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9965.tid new file mode 100644 index 0000000000..ecad671114 --- /dev/null +++ b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9965.tid @@ -0,0 +1,14 @@ +title: $:/changenotes/5.5.0/#9965 +created: 20260812171534862 +modified: 20260812171534862 +tags: $:/tags/ChangeNote +change-type: enhancement +change-category: usability +description: Change of the class attribute of editors does no more completely refresh the widget +release: 5.5.0 +github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9965 +github-contributors: BurningTreeC +type: text/vnd.tiddlywiki + +This pull request changes the way editors refresh when their `class` attribute changes. +They did refresh the widget completely. Now they just assign the new classes. From 6c8ac9b6a7d596e11c1151a70d4c825c5377de17 Mon Sep 17 00:00:00 2001 From: Simon Huber Date: Fri, 14 Aug 2026 08:31:20 +0200 Subject: [PATCH 5/6] Refactor class attributes for edit field wrapper (#9879) * Refactor class attributes for edit field wrapper The problem here is, that if we have an existing field with name - say - "field1" and we want to add a field with name "field12345", at the moment we insert "field1" the edit-text widget re-renders because its classes change. The `tc-edit-field-exists` class must go outside to the container div. * Add changenote for bugfix in field-name inputs Fixes the field-name input re-rendering issue that caused loss of focus when inserting existing field-names. --- core/ui/EditTemplate/fields.tid | 6 +++--- editions/tw5.com/tiddlers/releasenotes/5.4.1/#9879.tid | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 editions/tw5.com/tiddlers/releasenotes/5.4.1/#9879.tid diff --git a/core/ui/EditTemplate/fields.tid b/core/ui/EditTemplate/fields.tid index 8a09f74db6..946c835eb6 100644 --- a/core/ui/EditTemplate/fields.tid +++ b/core/ui/EditTemplate/fields.tid @@ -108,10 +108,10 @@ tags: $:/tags/EditTemplate storeTitle=<> searchListState=<> > -
+
get[text]] :intersection[fields[]] :then[[tc-edit-field-exists]] }$`> <$transclude $variable="keyboard-driven-input" cancelPopups="yes" - class=`tc-edit-texteditor tc-popup-handle ${ [get[text]] :intersection[fields[]] :then[[tc-edit-field-exists]] }$` + class="tc-edit-texteditor tc-popup-handle" configTiddlerFilter="[[$:/config/EditMode/fieldname-filter]]" default="" focus={{{ [{!!draft.of}is[tiddler]then{$:/config/AutoFocusEdit}match[fields]then[true]] :else[{$:/config/AutoFocus}match[fields]then[true]] :else[[false]] }}} @@ -178,4 +178,4 @@ tags: $:/tags/EditTemplate
- \ No newline at end of file + diff --git a/editions/tw5.com/tiddlers/releasenotes/5.4.1/#9879.tid b/editions/tw5.com/tiddlers/releasenotes/5.4.1/#9879.tid new file mode 100644 index 0000000000..93ddc19e22 --- /dev/null +++ b/editions/tw5.com/tiddlers/releasenotes/5.4.1/#9879.tid @@ -0,0 +1,10 @@ +title: $:/changenotes/5.4.1/#9879 +description: Fix field-name inputs re-render +tags: $:/tags/ChangeNote +release: 5.4.1 +change-type: bugfix +change-category: usability +github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9879 +github-contributors: BurningTreeC + +Fixes the field-name input re-rendering and therefor loosing focus when inserting a field-name that already exists From 5e5937838b90a55eda5e2b47177767353d7b68c4 Mon Sep 17 00:00:00 2001 From: Simon Huber Date: Fri, 14 Aug 2026 12:56:09 +0200 Subject: [PATCH 6/6] Fix: #9879 change release note for version 5.5.0 (#9968) --- .../tw5.com/tiddlers/releasenotes/{5.4.1 => 5.5.0}/#9879.tid | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename editions/tw5.com/tiddlers/releasenotes/{5.4.1 => 5.5.0}/#9879.tid (87%) diff --git a/editions/tw5.com/tiddlers/releasenotes/5.4.1/#9879.tid b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9879.tid similarity index 87% rename from editions/tw5.com/tiddlers/releasenotes/5.4.1/#9879.tid rename to editions/tw5.com/tiddlers/releasenotes/5.5.0/#9879.tid index 93ddc19e22..bc886a322d 100644 --- a/editions/tw5.com/tiddlers/releasenotes/5.4.1/#9879.tid +++ b/editions/tw5.com/tiddlers/releasenotes/5.5.0/#9879.tid @@ -1,7 +1,7 @@ -title: $:/changenotes/5.4.1/#9879 +title: $:/changenotes/5.5.0/#9879 description: Fix field-name inputs re-render tags: $:/tags/ChangeNote -release: 5.4.1 +release: 5.5.0 change-type: bugfix change-category: usability github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9879