From 6598455e830f35a32e499fc55fb3057e5cd63f61 Mon Sep 17 00:00:00 2001 From: Karl Knechtel Date: Sat, 3 Oct 2015 08:32:47 -0400 Subject: [PATCH 1/4] Create Filter Operators.tid --- .../dev/tiddlers/new/Filter Operators.tid | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 editions/dev/tiddlers/new/Filter Operators.tid diff --git a/editions/dev/tiddlers/new/Filter Operators.tid b/editions/dev/tiddlers/new/Filter Operators.tid new file mode 100644 index 000000000..2bf019915 --- /dev/null +++ b/editions/dev/tiddlers/new/Filter Operators.tid @@ -0,0 +1,94 @@ +tags: dev +title: Filter Operators +type: text/vnd.tiddlywiki + +! Overview + +Filter operators are modules (tiddlers of type `application/javascript`) with their `module-type` field set to `filteroperator`, exporting one or more functions implementing a filter. + +Each function will be called with three arguments: + +* A [[tiddler iterator|Tiddler Iterators]] representing the results of the previous filter step (or all tiddlers, if this filter appears first in an expression), conventionally named `source`. +* An object, conventionally called `operator`, representing the arguments for this filter step, with the following keys: +** //operator//: the name of the filter operator specified in the WikiText; +** //operand//: the operand for the filter step (as a string; if the filter specified it in angle brackets or braces, the text reference or variable name will have already been resolved); +** //prefix//: (optional) a string containing a single exclamation mark if the filter operator is to be negated; +** //suffix//: (optional) a string containing an additional filter argument (typically a tiddler field name) following the filter name (separated by a colon in the filter syntax); +** //regexp//: (optional, deprecated) used instead of //operand// if the filter operand is a regexp. +* An object, conventionally called `options`, with the following keys: +** //wiki//: The $tw.Wiki object; +** //widget//: (optional) a widget node. + +The function should return either a new [[tiddler iterator|Tiddler Iterators]], or else an array of tiddler titles (as strings). The underlying filter mechanism will convert back and forth between iterators and arrays as needed. + +Normally + +! References + +There are several filter operators built into the core which can serve as a jumping off point for your own filter operators: + +https://github.com/Jermolene/TiddlyWiki5/tree/master/core/modules/filters + +! Example + +Suppose we want to make a filter operator that returns every other tiddler from the input list. A typical invocation might look like `[tags[interesting]everyother[]]`. + +We make a new tiddler, set its `type` and `module-type` appropriately, and begin writing the code: + + (function(){ + "use strict"; + + exports.everyother = function(source, operator, options) { + // TODO + } + })(); + +For the example filter syntax, our function will be called with + +* source: an iterator over all the tiddlers tagged as `interesting` +* operator: an object {operator: "everyother", operand: ""} +* options: an object with the current Wiki object and a widget object, neither of which we need + +As is usually the case, we don't care about `operator.operator` here (since that information has already been used to look up our function); we also don't care about `operator.operand`, since there is no meaningful operand for this operation. + +We could implement the operator by iterating over the input tiddlers and explicitly building a result array of titles: + + (function(){ + "use strict"; + + exports.everyother = function(source, operator, options) { + var result = []; + var include = true; + source(function(tiddler, title) { + if (include) { result.push(title); } + include = !include; + }); + return result; + } + })(); + +That is, we supply a callback to `source` that negates `include` each time through (in order to grab every other result) and pushes the `title` of every other tiddler onto the result. + +Alternatively, we can return our own iterator, by returning a function that accepts a similar callback and only calls it on every other tiddler: + + (function(){ + "use strict"; + + exports.everyother = function(source, operator, options) { + return function(callback) { + var include = true; + source(function(tiddler, title) { + if (include) { callback(tiddler, title); } + include = !include; + }); + }; + } + })(); + +Either way, we could interpret the `!` flag on the filter, if present, to mean that we want the //other// half of the tiddlers, by using it to set the initial value of `include`: + + var include = operator.prefix !== "!"; + +! Filter Behaviour + +As with [JavaScript Macros], filter operators should not make modifications to tiddlers, but only return a list of tiddlers or a tiddler iterator. From b23d53e9b097bcf4639a07c6d5c30f7ed6a9caf6 Mon Sep 17 00:00:00 2001 From: Karl Knechtel Date: Sat, 3 Oct 2015 08:36:56 -0400 Subject: [PATCH 2/4] Fix stray line --- editions/dev/tiddlers/new/Filter Operators.tid | 2 -- 1 file changed, 2 deletions(-) diff --git a/editions/dev/tiddlers/new/Filter Operators.tid b/editions/dev/tiddlers/new/Filter Operators.tid index 2bf019915..88a12d939 100644 --- a/editions/dev/tiddlers/new/Filter Operators.tid +++ b/editions/dev/tiddlers/new/Filter Operators.tid @@ -21,8 +21,6 @@ Each function will be called with three arguments: The function should return either a new [[tiddler iterator|Tiddler Iterators]], or else an array of tiddler titles (as strings). The underlying filter mechanism will convert back and forth between iterators and arrays as needed. -Normally - ! References There are several filter operators built into the core which can serve as a jumping off point for your own filter operators: From d806f1d0f138d5b64b050e7d23de1ce7fbe3bc35 Mon Sep 17 00:00:00 2001 From: Karl Knechtel Date: Sat, 3 Oct 2015 08:42:56 -0400 Subject: [PATCH 3/4] Assorted wikitext fixes --- .../dev/tiddlers/new/Filter Operators.tid | 74 ++++++++++--------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/editions/dev/tiddlers/new/Filter Operators.tid b/editions/dev/tiddlers/new/Filter Operators.tid index 88a12d939..44fec68b8 100644 --- a/editions/dev/tiddlers/new/Filter Operators.tid +++ b/editions/dev/tiddlers/new/Filter Operators.tid @@ -33,60 +33,64 @@ Suppose we want to make a filter operator that returns every other tiddler from We make a new tiddler, set its `type` and `module-type` appropriately, and begin writing the code: - (function(){ - "use strict"; +``` +(function(){ +"use strict"; - exports.everyother = function(source, operator, options) { - // TODO - } - })(); +exports.everyother = function(source, operator, options) { + // TODO +} +})(); +``` For the example filter syntax, our function will be called with * source: an iterator over all the tiddlers tagged as `interesting` -* operator: an object {operator: "everyother", operand: ""} +* operator: an object `{operator: "everyother", operand: ""}` * options: an object with the current Wiki object and a widget object, neither of which we need As is usually the case, we don't care about `operator.operator` here (since that information has already been used to look up our function); we also don't care about `operator.operand`, since there is no meaningful operand for this operation. We could implement the operator by iterating over the input tiddlers and explicitly building a result array of titles: - (function(){ - "use strict"; +``` +(function(){ +"use strict"; - exports.everyother = function(source, operator, options) { - var result = []; - var include = true; - source(function(tiddler, title) { - if (include) { result.push(title); } - include = !include; - }); - return result; - } - })(); +exports.everyother = function(source, operator, options) { + var result = []; + var include = true; + source(function(tiddler, title) { + if (include) { result.push(title); } + include = !include; + }); + return result; +} +})(); +``` That is, we supply a callback to `source` that negates `include` each time through (in order to grab every other result) and pushes the `title` of every other tiddler onto the result. Alternatively, we can return our own iterator, by returning a function that accepts a similar callback and only calls it on every other tiddler: - (function(){ - "use strict"; +``` +(function(){ +"use strict"; - exports.everyother = function(source, operator, options) { - return function(callback) { - var include = true; - source(function(tiddler, title) { - if (include) { callback(tiddler, title); } - include = !include; - }); - }; - } - })(); +exports.everyother = function(source, operator, options) { + return function(callback) { + var include = true; + source(function(tiddler, title) { + if (include) { callback(tiddler, title); } + include = !include; + }); + }; +} +})(); +``` -Either way, we could interpret the `!` flag on the filter, if present, to mean that we want the //other// half of the tiddlers, by using it to set the initial value of `include`: - - var include = operator.prefix !== "!"; +Either way, we could interpret the `!` flag on the filter, if present, to mean that we want the //other// half of the tiddlers, by using it to set the initial value of `include`: `var include = operator.prefix !== "!";` ! Filter Behaviour -As with [JavaScript Macros], filter operators should not make modifications to tiddlers, but only return a list of tiddlers or a tiddler iterator. +As with [[JavaScript Macros]], filter operators should not make modifications to tiddlers, but only return a list of tiddlers or a tiddler iterator. From 3ab7db1a592e7ede7a765c828d79e1bfedc0d012 Mon Sep 17 00:00:00 2001 From: Karl Knechtel Date: Sat, 3 Oct 2015 08:43:55 -0400 Subject: [PATCH 4/4] One more fix --- editions/dev/tiddlers/new/Filter Operators.tid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editions/dev/tiddlers/new/Filter Operators.tid b/editions/dev/tiddlers/new/Filter Operators.tid index 44fec68b8..19c99a51f 100644 --- a/editions/dev/tiddlers/new/Filter Operators.tid +++ b/editions/dev/tiddlers/new/Filter Operators.tid @@ -16,7 +16,7 @@ Each function will be called with three arguments: ** //suffix//: (optional) a string containing an additional filter argument (typically a tiddler field name) following the filter name (separated by a colon in the filter syntax); ** //regexp//: (optional, deprecated) used instead of //operand// if the filter operand is a regexp. * An object, conventionally called `options`, with the following keys: -** //wiki//: The $tw.Wiki object; +** //wiki//: The `$tw.Wiki` object; ** //widget//: (optional) a widget node. The function should return either a new [[tiddler iterator|Tiddler Iterators]], or else an array of tiddler titles (as strings). The underlying filter mechanism will convert back and forth between iterators and arrays as needed.