Repository: TiddlyWiki/TiddlyWiki5 (JavaScript)

Issue:
[BUG] ActionListOpsWidget breaks with input titles starting with a dash
The `<$action-listops>` widget breaks with input titles starting with a dash. For example, if the tiddler "target" contains the text `-3` then the following will not work as expected:

```
<$action-listops  $tiddler="target" $field="text" $subfilter="+[toggle[-3]]"/>
```

In this case, the text field of "target" is not left untouched, and the "-3" item is not removed.

But, the same experiment with "foobar" instead of "-3" works as expected.

The problem is here:

https://github.com/Jermolene/TiddlyWiki5/blob/c741978e959c2608fa01dcd881d47194ccdf79b8/core/modules/widgets/action-listops.js#L72-L76

The code makes the assumption that a stringified list can be evaluated as a filter and will get the same results. That assumption fails if the list item starts with a dash, as it is interpreted as the `:except` filter run prefix.




Discussion:
I have no idea if it is the same problem but titles starting with a `+` also seem to misbehave. If the target tiddler is blank and you toggle it once it works, but clicking again adds a second copy of the operand but without the `+`. 
The same problem happens for titles that start with **any** symbol that can start a filter run: `+ - = ~ : `
It should also occur for `[` and `]`, but these have to be contained in variable operands, since they can't be used as literal operand values because of the enclosing square brackets used by the filter operator syntax; i.e., `$subfilter="+[toggle<var>]"`
We've already explored one potential fix: updating `$tw.utils.stringifyList()` to ensure that it add double square bracket quotes around titles that start with problematic characters (we would also presumably want to wrap blank values, which are currently ignored – see #1451)

* Ticket #4084 discusses the problem
* PR #4087 was merged with the changes to stringifyList
* #4248 discusses a potential problem with the fix that we decided was actually the intended behaivour
* PR #4249 reverts the changes in #4087

On the basis of those previous discussions, I think we need to explore other solutions. In particular, we might be able to provide the input list as the source for the filter evaluation, and prefix the subfilter with `[all[]] ` for evaluation to get the titles back.

This is now fixed in #6540, let me know how you get on @ericshulman 



Patch:
diff --git a/core/modules/widgets/action-listops.js b/core/modules/widgets/action-listops.js
index 802fcaa76a2..d8e27464429 100644
--- a/core/modules/widgets/action-listops.js
+++ b/core/modules/widgets/action-listops.js
@@ -1,3 +1,5 @@
+const { makeTiddlerIterator } = require("../wiki");
+
 /*\
 title: $:/core/modules/widgets/action-listops.js
 type: application/javascript
@@ -71,8 +73,8 @@ ActionListopsWidget.prototype.invokeAction = function(triggeringWidget,
 	}
 	if(this.subfilter) {
 		var inputList = this.wiki.getTiddlerList(this.target,field,index),
-			subfilter = $tw.utils.stringifyList(inputList) + " " + this.subfilter;
-		this.wiki.setText(this.target, field, index, $tw.utils.stringifyList(this.wiki.filterTiddlers(subfilter,this)));
+			subfilter = "[all[]] " + this.subfilter;
+		this.wiki.setText(this.target, field, index, $tw.utils.stringifyList(this.wiki.filterTiddlers(subfilter,this,this.wiki.makeTiddlerIterator(inputList))));
 	}
 	if(this.filtertags) {
 		var tiddler = this.wiki.getTiddler(this.target),


Test patch:
diff --git a/editions/test/tiddlers/tests/test-action-widgets.js b/editions/test/tiddlers/tests/test-action-widgets.js
new file mode 100644
index 00000000000..12311521b10
--- /dev/null
+++ b/editions/test/tiddlers/tests/test-action-widgets.js
@@ -0,0 +1,55 @@
+/*\
+title: test-action-widgets.js
+type: application/javascript
+tags: [[$:/tags/test-spec]]
+
+Tests the action widgets.
+
+\*/
+(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("Action widget tests", function() {
+
+function setupWiki(wikiOptions) {
+	wikiOptions = wikiOptions || {};
+	// Create a wiki
+	var wiki = new $tw.Wiki(wikiOptions);
+	var tiddlers = [{
+		title: "Root",
+		text: "Some dummy content"
+	}];
+	wiki.addTiddlers(tiddlers);
+	wiki.addIndexersToWiki();
+	var widgetNode = wiki.makeTranscludeWidget("Root",{document: $tw.fakeDocument, parseAsInline: true});
+	var container = $tw.fakeDocument.createElement("div");
+	widgetNode.render(container,null);
+	return {
+		wiki: wiki,
+		widgetNode: widgetNode,
+		contaienr: container
+	};
+}
+
+it("should handle the action-listops widget", function() {
+	var info = setupWiki();
+	var invokeActions = function(actions) {
+		info.widgetNode.invokeActionString(actions,info.widgetNode,null,{});
+	};
+	invokeActions("<$action-setfield $tiddler='Output' $field='text' $value='Elephants!'/>");
+	expect(info.wiki.getTiddlerText("Output")).toBe("Elephants!");
+	invokeActions("<$action-listops  $tiddler='Output' $field='text' $subfilter='+[toggle[-3]]'/>");
+	expect(info.wiki.getTiddlerText("Output")).toBe("Elephants! -3");
+	invokeActions("<$action-listops  $tiddler='Output' $field='text' $subfilter='+[toggle[-3]]'/>");
+	expect(info.wiki.getTiddlerText("Output")).toBe("Elephants!");
+});
+
+});
+
+})();
+