diff --git a/core/modules/filters/range.js b/core/modules/filters/range.js new file mode 100644 index 000000000..d51822b7f --- /dev/null +++ b/core/modules/filters/range.js @@ -0,0 +1,80 @@ +/*\ +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 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 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; +}; + +})(); diff --git a/editions/tw5.com/tiddlers/filters/range.tid b/editions/tw5.com/tiddlers/filters/range.tid new file mode 100644 index 000000000..0b6fdf96b --- /dev/null +++ b/editions/tw5.com/tiddlers/filters/range.tid @@ -0,0 +1,59 @@ +created: 20171221184734665 +modified: 20171229211834620 +tags: [[Filter Operators]] [[Negatable Operators]] +title: range Operator +type: text/vnd.tiddlywiki +caption: range +op-purpose: generate a range of numbers +op-input: ignored +op-parameter: a range specification, like `[1,5]` +op-parameter-name: N +op-output: a series of evenly spaced numbers ranging from `` to `` + +\define range_example(range) +``` +[range[$range$]] +``` + +<$list variable=n filter="[range[$range$]]"><> +\end + +The `range` operator allows a range of numbers to be enumerated, similar to a `for` loop in other programming languages. It's useful in combination with the [[Formula Plugin]]. + +|!Purpose|produce a range of numbers| +|!Input|ignored.| +|!Parameter|1-3 numbers separated by `,` or `;`.| +|!Output|A range of numbers starting with | +|!`!` Output|As ''Output'', but with order reversed.| + +The parameter has three forms: + +* `` +* `,` +* `,,` + +Each part must be a number, and works as follows: + +* ``: start counting at this number. Defaults to 0. +* ``: stop counting at this number. +** It will be included unless it falls between two steps. +* ``: count up (or down) by this amount. +** It may be negated so it counts in the right direction. +** It cannot be zero. + +The number of decimal points in the output is fixed, and based on the parameter with the //most// decimal points. + +To prevent the browser from freezing, `range` is currently limited to 10,000 values. + + +!!Examples + +<> + +<> + +<> + +<> + +<> \ No newline at end of file