1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-20 17:09:52 +00:00

Fixes variable enumeration in widgets (#9648)

* fix: variable enumeration in widgets

* fix: fakeWidget should have a variables property

* fix: don't use spread properties

* fix: resolve more embarassing bugs

* chore: tests and whitespace

* fix: simplify opts check
This commit is contained in:
Saq Imtiaz
2026-02-19 12:14:19 +01:00
committed by GitHub
parent c305eb01eb
commit 08f2b8bdf4
10 changed files with 69 additions and 45 deletions

View File

@@ -24,7 +24,7 @@ exports.cascade = function(operationSubFunction,options) {
}
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler","")
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
}));
if(output.length !== 0) {
result = output[0];

View File

@@ -18,7 +18,7 @@ exports.filter = function(operationSubFunction,options) {
results.each(function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",""),
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
"index": "" + index,
"revIndex": "" + (results.length - 1 - index),
"length": "" + results.length

View File

@@ -20,7 +20,7 @@ exports.map = function(operationSubFunction,options) {
$tw.utils.each(inputTitles,function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",""),
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
"index": "" + index,
"revIndex": "" + (inputTitles.length - 1 - index),
"length": "" + inputTitles.length

View File

@@ -17,7 +17,7 @@ exports.reduce = function(operationSubFunction,options) {
results.each(function(title) {
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler"),
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
"index": "" + index,
"revIndex": "" + (results.length - 1 - index),
"length": "" + results.length,

View File

@@ -24,7 +24,7 @@ exports.sort = function(operationSubFunction,options) {
results.each(function(title) {
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler")
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
}));
sortKeys.push(key[0] || "");
});

View File

@@ -19,7 +19,7 @@ exports.filter = function(source,operator,options) {
source(function(tiddler,title) {
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": options.widget.getVariable("currentTiddler","")
"..currentTiddler": options.widget.getVariable("currentTiddler",{defaultValue:""})
}));
if((list.length > 0) === target) {
results.push(title);

View File

@@ -24,4 +24,4 @@ exports.variables = function(source,operator,options) {
}
}
return names.sort();
};
};

View File

@@ -329,48 +329,43 @@ Widget.prototype.getStateQualifier = function(name) {
/*
Make a fake widget with specified variables, suitable for variable lookup in filters. Each variable can be a string or an array of strings
*/
Widget.prototype.makeFakeWidgetWithVariables = function(variables) {
var self = this,
variables = variables || {};
return {
getVariable: function(name,opts) {
if($tw.utils.hop(variables,name)) {
var value = variables[name];
if($tw.utils.isArray(value)) {
return value[0];
} else {
return value;
}
} else {
opts = opts || {};
opts.variables = $tw.utils.extend({},variables,opts.variables);
return self.getVariable(name,opts);
};
Widget.prototype.makeFakeWidgetWithVariables = function(vars = {}) {
const self = this;
const fakeWidget = {
getVariableInfo(name,opts = {}) {
if(name in vars) {
const value = vars[name];
return Array.isArray(value)
? { text: value[0], resultList: value }
: { text: value, resultList: [value] };
}
opts = opts || {};
opts.variables = Object.assign({}, vars, opts.variables || {});
return self.getVariableInfo(name, opts);
},
getVariableInfo: function(name,opts) {
if($tw.utils.hop(variables,name)) {
var value = variables[name];
if($tw.utils.isArray(value)) {
return {
text: value[0],
resultList: value
};
} else {
return {
text: value,
resultList: [value]
};
}
} else {
opts = opts || {};
opts.variables = $tw.utils.extend({},variables,opts.variables);
return self.getVariableInfo(name,opts);
};
getVariable(name,opts) {
return this.getVariableInfo(name, opts).text;
},
makeFakeWidgetWithVariables: self.makeFakeWidgetWithVariables,
resolveVariableParameters: self.resolveVariableParameters,
wiki: self.wiki
wiki: self.wiki,
makeFakeWidgetWithVariables: self.makeFakeWidgetWithVariables,
get variables() {
// Merge parent vars via prototype-like delegation
return Object.create(self.variables || {},
Object.keys(vars).reduce((acc, key) => {
acc[key] = { value: vars[key], enumerable: true, configurable: true };
return acc;
}, {})
);
}
};
return fakeWidget;
};
/*

View File

@@ -0,0 +1,15 @@
title: Functions/VariableLeakage
description: Variables from filter runs or functions should not pollute widget
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\function myvar(element) [<element>]
\function call(element) [[myvar]is[variable]then<element>]
<<call abc>>
+
title: ExpectedResult
<p>abc</p>

View File

@@ -0,0 +1,14 @@
title: Functions/VariableEnumeration
description: Variables should be enumerable within functions
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\function list-vars() [variables[]]
<$text text={{{ [function[list-vars]count[]compare:number:gt[0]then[yes]] }}}/>
+
title: ExpectedResult
<p>yes</p>