1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-07-05 11:43:16 +00:00
TiddlyWiki5/core/modules/filters/range.js
2018-07-19 21:42:09 +01:00

81 lines
1.9 KiB
JavaScript

/*\
title: $:/core/modules/filters/range.js
type: application/javascript
module-type: filteroperator
Filter operator for generating a numeric range.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.range = function(source,operator,options) {
var results = [];
// Split the operand into numbers delimited by these symbols
var parts = operator.operand.split(/[,:;]/g), beg, end, inc, i, fixed = 0;
for (i = 0; i < parts.length; ++i) {
// Validate real number
if (!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i]))
return ["range: bad number \""+parts[i]+"\""];
// Count digits; the most precise number determines decimal places in output.
var frac = /\.\d+/.exec(parts[i]);
if (frac) fixed = Math.max(fixed, frac[0].length-1);
parts[i] = parseFloat(parts[i]);
}
switch (parts.length) {
case 1:
beg = 0;
end = parts[0];
inc = 1;
break;
case 2:
beg = parts[0];
end = parts[1];
inc = 1;
break;
case 3:
beg = parts[0];
end = parts[1];
inc = Math.abs(parts[2]);
break;
}
if (inc === 0) return ["range: increment 0 causes infinite loop"];
// May need to count backwards
var direction = ((end<beg) ? -1 : 1);
inc *= direction;
// Estimate number of resulting elements
if ((end-beg)/inc > 10000) return ["range: too many steps (over 10K)"];
// Avoid rounding error on last step
end += direction * 0.5 * Math.pow(0.1, fixed);
var safety = 10010;
// Enumerate the range
if (end<beg) {for (i = beg; i > end; i += inc) {results.push(i.toFixed(fixed)); if (--safety<0) break;}}
else {for (i = beg; i < end; i += inc) {results.push(i.toFixed(fixed)); if (--safety<0) break;}}
if (safety<0) return ["range: unexpectedly large output"];
// Reverse?
if (operator.prefix === "!") results.reverse();
return results;
};
})();