mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-04-07 19:26:39 +00:00
Merge 9627f2b6b2681496b95ba015c9cfaf146b891905 into 06adaf3331d983be822a40c10677fa05f6ea4536
This commit is contained in:
commit
4626ebb8bb
@ -200,12 +200,20 @@ exports.parseFilter = function(filterString) {
|
||||
|
||||
exports.getFilterOperators = function() {
|
||||
if(!this.filterOperators) {
|
||||
$tw.Wiki.prototype.filterOperators = {};
|
||||
$tw.modules.applyMethods("filteroperator",this.filterOperators);
|
||||
$tw.Wiki.prototype.oldFilterOperators = {};
|
||||
$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;
|
||||
};
|
||||
|
||||
exports.isFilterOperatorNew = function(name) {
|
||||
this.getFilterOperators();
|
||||
return name in $tw.Wiki.prototype.newFilterOperators;
|
||||
};
|
||||
|
||||
exports.getFilterRunPrefixes = function() {
|
||||
if(!this.filterRunPrefixes) {
|
||||
$tw.Wiki.prototype.filterRunPrefixes = {};
|
||||
@ -214,11 +222,21 @@ exports.getFilterRunPrefixes = function() {
|
||||
return this.filterRunPrefixes;
|
||||
}
|
||||
|
||||
exports.filterTiddlers = function(filterString,widget,source) {
|
||||
exports.filterTiddlersPolymorphic = function(filterString,widget,source) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
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:
|
||||
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");
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operands = [],
|
||||
operatorFunction;
|
||||
operatorFunction,
|
||||
operatorName;
|
||||
if(!operator.operator) {
|
||||
// Use the "title" operator if no operator is specified
|
||||
operatorFunction = filterOperators.title;
|
||||
operatorName = "title";
|
||||
} 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
|
||||
operatorFunction = filterOperators["[unknown]"];
|
||||
} else {
|
||||
// Use the operator function
|
||||
operatorFunction = filterOperators[operator.operator];
|
||||
operatorName = operator.operator;
|
||||
}
|
||||
$tw.utils.each(operator.operands,function(operand) {
|
||||
if(operand.indirect) {
|
||||
@ -277,7 +298,17 @@ exports.compileFilter = function(filterString) {
|
||||
}
|
||||
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
|
||||
results = operatorFunction(accumulator,{
|
||||
operator: operator.operator,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/count.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
module-type: newfilteroperator
|
||||
|
||||
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) {
|
||||
count++;
|
||||
});
|
||||
return [count + ""];
|
||||
return [count];
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/json-ops.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
module-type: newfilteroperator
|
||||
|
||||
Filter operators for JSON operations
|
||||
|
||||
@ -57,9 +57,9 @@ exports["jsonindexes"] = function(source,operator,options) {
|
||||
exports["jsontype"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,title);
|
||||
if(data) {
|
||||
var item = getDataItemType(data,operator.operands);
|
||||
var data = $tw.utils.filterItemToObject(title,{defaultValue: title,parseStringsAsJson: true});
|
||||
if(data !== undefined) {
|
||||
var item = getFilterItemType(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push(item);
|
||||
}
|
||||
@ -196,7 +196,7 @@ function convertDataItemKeysToStrings(item) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function getDataItemType(data,indexes) {
|
||||
function getFilterItemType(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item type
|
||||
@ -281,4 +281,3 @@ function setDataItem(data,indexes,value) {
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/math.js
|
||||
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.
|
||||
|
||||
@ -207,7 +207,7 @@ function makeNumericBinaryOperator(fnCalc) {
|
||||
var result = [],
|
||||
numOperand = $tw.utils.parseNumber(operator.operand);
|
||||
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;
|
||||
};
|
||||
@ -226,7 +226,7 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
||||
if(fnFinal) {
|
||||
value = fnFinal(value,result.length,result);
|
||||
}
|
||||
return [$tw.utils.stringifyNumber(value)];
|
||||
return [value];
|
||||
};
|
||||
};
|
||||
|
||||
@ -238,7 +238,7 @@ function makeNumericArrayOperator(fnCalc) {
|
||||
});
|
||||
results = fnCalc(results);
|
||||
$tw.utils.each(results,function(value,index) {
|
||||
results[index] = $tw.utils.stringifyNumber(value);
|
||||
results[index] = value;
|
||||
});
|
||||
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);
|
||||
};
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
it("should handle type conversions", function() {
|
||||
expect(wiki.filterTiddlers("[[2]add[2]addprefix[donkey]]").join(",")).toBe("donkey4");
|
||||
});
|
||||
|
||||
/* listops filters */
|
||||
|
||||
it("should handle the allafter operator", function() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user