mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-08-07 22:33:50 +00:00
Merge 9627f2b6b2681496b95ba015c9cfaf146b891905 into 06adaf3331d983be822a40c10677fa05f6ea4536
This commit is contained in:
commit
4626ebb8bb
@ -200,12 +200,20 @@ exports.parseFilter = function(filterString) {
|
|||||||
|
|
||||||
exports.getFilterOperators = function() {
|
exports.getFilterOperators = function() {
|
||||||
if(!this.filterOperators) {
|
if(!this.filterOperators) {
|
||||||
$tw.Wiki.prototype.filterOperators = {};
|
$tw.Wiki.prototype.oldFilterOperators = {};
|
||||||
$tw.modules.applyMethods("filteroperator",this.filterOperators);
|
$tw.modules.applyMethods("filteroperator",this.oldFilterOperators);
|
||||||
|
$tw.Wiki.prototype.newFilterOperators = {};
|
||||||
|
$tw.modules.applyMethods("newfilteroperator",this.newFilterOperators);
|
||||||
|
$tw.Wiki.prototype.filterOperators = $tw.utils.extend({},$tw.Wiki.prototype.oldFilterOperators,$tw.Wiki.prototype.newFilterOperators);
|
||||||
}
|
}
|
||||||
return this.filterOperators;
|
return this.filterOperators;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.isFilterOperatorNew = function(name) {
|
||||||
|
this.getFilterOperators();
|
||||||
|
return name in $tw.Wiki.prototype.newFilterOperators;
|
||||||
|
};
|
||||||
|
|
||||||
exports.getFilterRunPrefixes = function() {
|
exports.getFilterRunPrefixes = function() {
|
||||||
if(!this.filterRunPrefixes) {
|
if(!this.filterRunPrefixes) {
|
||||||
$tw.Wiki.prototype.filterRunPrefixes = {};
|
$tw.Wiki.prototype.filterRunPrefixes = {};
|
||||||
@ -214,11 +222,21 @@ exports.getFilterRunPrefixes = function() {
|
|||||||
return this.filterRunPrefixes;
|
return this.filterRunPrefixes;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.filterTiddlers = function(filterString,widget,source) {
|
exports.filterTiddlersPolymorphic = function(filterString,widget,source) {
|
||||||
var fn = this.compileFilter(filterString);
|
var fn = this.compileFilter(filterString);
|
||||||
return fn.call(this,source,widget);
|
return fn.call(this,source,widget);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.filterTiddlers = function(filterString,widget,source) {
|
||||||
|
var results = this.filterTiddlersPolymorphic(filterString,widget,source);
|
||||||
|
for(var t=0; t<results.length; t++) {
|
||||||
|
if(typeof results[t] !== "string") {
|
||||||
|
results[t] = $tw.utils.filterItemToString(results[t]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compile a filter into a function with the signature fn(source,widget) where:
|
Compile a filter into a function with the signature fn(source,widget) where:
|
||||||
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
||||||
@ -255,16 +273,19 @@ exports.compileFilter = function(filterString) {
|
|||||||
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||||
$tw.utils.each(operation.operators,function(operator) {
|
$tw.utils.each(operation.operators,function(operator) {
|
||||||
var operands = [],
|
var operands = [],
|
||||||
operatorFunction;
|
operatorFunction,
|
||||||
|
operatorName;
|
||||||
if(!operator.operator) {
|
if(!operator.operator) {
|
||||||
// Use the "title" operator if no operator is specified
|
// Use the "title" operator if no operator is specified
|
||||||
operatorFunction = filterOperators.title;
|
operatorFunction = filterOperators.title;
|
||||||
|
operatorName = "title";
|
||||||
} else if(!filterOperators[operator.operator]) {
|
} else if(!filterOperators[operator.operator]) {
|
||||||
// Unknown operators treated as "[unknown]" - at run time we can distinguish between a custom operator and falling back to the default "field" operator
|
// Unknown operators treated as "[unknown]" - at run time we can distinguish between a custom operator and falling back to the default "field" operator
|
||||||
operatorFunction = filterOperators["[unknown]"];
|
operatorFunction = filterOperators["[unknown]"];
|
||||||
} else {
|
} else {
|
||||||
// Use the operator function
|
// Use the operator function
|
||||||
operatorFunction = filterOperators[operator.operator];
|
operatorFunction = filterOperators[operator.operator];
|
||||||
|
operatorName = operator.operator;
|
||||||
}
|
}
|
||||||
$tw.utils.each(operator.operands,function(operand) {
|
$tw.utils.each(operator.operands,function(operand) {
|
||||||
if(operand.indirect) {
|
if(operand.indirect) {
|
||||||
@ -277,7 +298,17 @@ exports.compileFilter = function(filterString) {
|
|||||||
}
|
}
|
||||||
operands.push(operand.value);
|
operands.push(operand.value);
|
||||||
});
|
});
|
||||||
|
// If this is a legacy monomorphic operator then wrap the accumulator source in a wrapper that converts each item to a string
|
||||||
|
if(!self.isFilterOperatorNew(operatorName)) {
|
||||||
|
var innerAccumulator = accumulator;
|
||||||
|
accumulator = function(iterator) {
|
||||||
|
innerAccumulator(function(ignored,item) {
|
||||||
|
var title = $tw.utils.filterItemToString(item),
|
||||||
|
tiddler = self.getTiddler(title);
|
||||||
|
iterator(tiddler,title);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
// Invoke the appropriate filteroperator module
|
// Invoke the appropriate filteroperator module
|
||||||
results = operatorFunction(accumulator,{
|
results = operatorFunction(accumulator,{
|
||||||
operator: operator.operator,
|
operator: operator.operator,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*\
|
/*\
|
||||||
title: $:/core/modules/filters/count.js
|
title: $:/core/modules/filters/count.js
|
||||||
type: application/javascript
|
type: application/javascript
|
||||||
module-type: filteroperator
|
module-type: newfilteroperator
|
||||||
|
|
||||||
Filter operator returning the number of entries in the current list.
|
Filter operator returning the number of entries in the current list.
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ exports.count = function(source,operator,options) {
|
|||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
count++;
|
count++;
|
||||||
});
|
});
|
||||||
return [count + ""];
|
return [count];
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*\
|
/*\
|
||||||
title: $:/core/modules/filters/json-ops.js
|
title: $:/core/modules/filters/json-ops.js
|
||||||
type: application/javascript
|
type: application/javascript
|
||||||
module-type: filteroperator
|
module-type: newfilteroperator
|
||||||
|
|
||||||
Filter operators for JSON operations
|
Filter operators for JSON operations
|
||||||
|
|
||||||
@ -57,9 +57,9 @@ exports["jsonindexes"] = function(source,operator,options) {
|
|||||||
exports["jsontype"] = function(source,operator,options) {
|
exports["jsontype"] = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var data = $tw.utils.parseJSONSafe(title,title);
|
var data = $tw.utils.filterItemToObject(title,{defaultValue: title,parseStringsAsJson: true});
|
||||||
if(data) {
|
if(data !== undefined) {
|
||||||
var item = getDataItemType(data,operator.operands);
|
var item = getFilterItemType(data,operator.operands);
|
||||||
if(item !== undefined) {
|
if(item !== undefined) {
|
||||||
results.push(item);
|
results.push(item);
|
||||||
}
|
}
|
||||||
@ -196,7 +196,7 @@ function convertDataItemKeysToStrings(item) {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDataItemType(data,indexes) {
|
function getFilterItemType(data,indexes) {
|
||||||
// Get the item
|
// Get the item
|
||||||
var item = getDataItem(data,indexes);
|
var item = getDataItem(data,indexes);
|
||||||
// Return the item type
|
// Return the item type
|
||||||
@ -281,4 +281,3 @@ function setDataItem(data,indexes,value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
/*\
|
/*\
|
||||||
title: $:/core/modules/filters/math.js
|
title: $:/core/modules/filters/math.js
|
||||||
type: application/javascript
|
type: application/javascript
|
||||||
module-type: filteroperator
|
module-type: newfilteroperator
|
||||||
|
|
||||||
Filter operators for math. Unary/binary operators work on each item in turn, and return a new item list.
|
Filter operators for math. Unary/binary operators work on each item in turn, and return a new item list.
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ function makeNumericBinaryOperator(fnCalc) {
|
|||||||
var result = [],
|
var result = [],
|
||||||
numOperand = $tw.utils.parseNumber(operator.operand);
|
numOperand = $tw.utils.parseNumber(operator.operand);
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
result.push($tw.utils.stringifyNumber(fnCalc($tw.utils.parseNumber(title),numOperand)));
|
result.push(fnCalc($tw.utils.parseNumber(title),numOperand));
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@ -226,7 +226,7 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
|||||||
if(fnFinal) {
|
if(fnFinal) {
|
||||||
value = fnFinal(value,result.length,result);
|
value = fnFinal(value,result.length,result);
|
||||||
}
|
}
|
||||||
return [$tw.utils.stringifyNumber(value)];
|
return [value];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -238,7 +238,7 @@ function makeNumericArrayOperator(fnCalc) {
|
|||||||
});
|
});
|
||||||
results = fnCalc(results);
|
results = fnCalc(results);
|
||||||
$tw.utils.each(results,function(value,index) {
|
$tw.utils.each(results,function(value,index) {
|
||||||
results[index] = $tw.utils.stringifyNumber(value);
|
results[index] = value;
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
86
core/modules/utils/simple-list.js
Normal file
86
core/modules/utils/simple-list.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*\
|
||||||
|
module-type: utils
|
||||||
|
title: $:/core/modules/utils/simple-list.js
|
||||||
|
type: application/javascript
|
||||||
|
|
||||||
|
Switched from a linked list to simplify things
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
function SimpleList() {
|
||||||
|
this.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperty(SimpleList.prototype,"length", {
|
||||||
|
get: function() {
|
||||||
|
return this.list.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SimpleList.prototype.clear = function() {
|
||||||
|
this.list = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleList.prototype.remove = function(value) {
|
||||||
|
if($tw.utils.isArray(value)) {
|
||||||
|
for(var t=0; t<value.length; t++) {
|
||||||
|
this._remove(value[t]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._remove(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Push behaves like array.push and accepts multiple string arguments. But it also
|
||||||
|
accepts a single array argument too, to be consistent with its other methods.
|
||||||
|
*/
|
||||||
|
SimpleList.prototype.push = function(/* values */) {
|
||||||
|
var values = arguments;
|
||||||
|
if(arguments.length === 1 && $tw.utils.isArray(values[0])) {
|
||||||
|
values = values[0];
|
||||||
|
}
|
||||||
|
for(var i = 0; i < values.length; i++) {
|
||||||
|
this._push(values[i]);
|
||||||
|
}
|
||||||
|
return this.list.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleList.prototype.pushTop = function(value) {
|
||||||
|
// this.push(value);
|
||||||
|
// -or-
|
||||||
|
$tw.utils.pushTop(this.list,value);
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleList.prototype.each = function(callback) {
|
||||||
|
$tw.utils.each(this.list,callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleList.prototype.toArray = function() {
|
||||||
|
return this.list.slice(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleList.prototype.makeTiddlerIterator = function(wiki) {
|
||||||
|
var self = this;
|
||||||
|
return function(callback) {
|
||||||
|
self.each(function(title) {
|
||||||
|
callback(wiki.getTiddler(title),title);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleList.prototype._remove = function(value) {
|
||||||
|
var p = this.list.indexOf(value);
|
||||||
|
if(p !== -1) {
|
||||||
|
this.list.splice(p,1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SimpleList.prototype._push = function(value) {
|
||||||
|
this.list.push(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.SimpleList = SimpleList;
|
||||||
|
|
||||||
|
})();
|
@ -1039,4 +1039,52 @@ exports.makeCompareFunction = function(type,options) {
|
|||||||
return (types[type] || types[options.defaultType] || types.number);
|
return (types[type] || types[options.defaultType] || types.number);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.filterItemToString = function(value) {
|
||||||
|
switch(typeof value) {
|
||||||
|
case "undefined":
|
||||||
|
return "undefined"
|
||||||
|
case "object":
|
||||||
|
return JSON.stringify(value);
|
||||||
|
case "boolean":
|
||||||
|
return value ? "true" : "false";
|
||||||
|
case "number":
|
||||||
|
return value.toString();
|
||||||
|
case "bigint":
|
||||||
|
return value.toString();
|
||||||
|
case "string":
|
||||||
|
return value;
|
||||||
|
case "symbol":
|
||||||
|
throw "Filter operators cannot return Symbols";
|
||||||
|
case "function":
|
||||||
|
throw "Filter operators cannot return Functions";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.filterItemToObject = function(value,options) {
|
||||||
|
options = options || {};
|
||||||
|
var defaultValue = options.defaultValue || {};
|
||||||
|
switch(typeof value) {
|
||||||
|
case "undefined":
|
||||||
|
return defaultValue;
|
||||||
|
case "object":
|
||||||
|
return value;
|
||||||
|
case "boolean":
|
||||||
|
return value;
|
||||||
|
case "number":
|
||||||
|
return value;
|
||||||
|
case "bigint":
|
||||||
|
return value;
|
||||||
|
case "string":
|
||||||
|
if(options.parseStringsAsJson) {
|
||||||
|
return $tw.utils.parseJSONSafe(value,defaultValue);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case "symbol":
|
||||||
|
throw "Filter operators cannot return Symbols";
|
||||||
|
case "function":
|
||||||
|
throw "Filter operators cannot return Functions";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -708,6 +708,10 @@ Tests the filtering mechanism.
|
|||||||
expect(wiki.filterTiddlers("1 2 3 4 +[min[2]]").join(",")).toBe("1,2,2,2");
|
expect(wiki.filterTiddlers("1 2 3 4 +[min[2]]").join(",")).toBe("1,2,2,2");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should handle type conversions", function() {
|
||||||
|
expect(wiki.filterTiddlers("[[2]add[2]addprefix[donkey]]").join(",")).toBe("donkey4");
|
||||||
|
});
|
||||||
|
|
||||||
/* listops filters */
|
/* listops filters */
|
||||||
|
|
||||||
it("should handle the allafter operator", function() {
|
it("should handle the allafter operator", function() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user