I have created a filter operator taggingtree[]
to collect all tiddlers within the tree beneath a tag (or a list of tags), i.e. all its children, the children’s children, and so on. I’ll post the complementary filter to get all of a tiddler’s (or a list of tiddlers’) parent tags, as well as the parents’ tags, and parents’ parents’ tags and so on, in a forthcoming reply to this post.
My use case ist this: In a very large wiki, search results are often overwhelming. Therefore, I build a list of all tags that appear within the tag hierarchy above the search results tiddlers and put these into a select
element. The select
element is then used to narrow down the search results to the selected topic which can be either broad (by selecting a tag in an upper level of the hierarchy) or narrow (by selecting a tag near the bottom). The present filter is used to build a list of all tiddlers beneath the selected tag which is then combined with the search results using the :intersection
filter run prefix.
Showing all wiki tags in the select
element is not useful when there are a lot of them, as in my case (1,000+). Showing only the immediate tags of the search results doesn’t help much if the tag hierarchy is very deep and one doesn’t know where exactly to look, i.e. it’s not much more useful than the results list itself.
Imagine you could limit search results on tiddlywiki.com to anything below Filters, be it filter operators or filter run prefixes and whatnot, without getting results for widgets or releases or whatever.
This works especially well if you put a button in the ViewToolbar that populates the select
element (or rather the tiddler tied to it) with the current tiddler and then puts the cursor into the search box. This way I can start a search in the hierarchy below that tiddler with a single button click. This has already saved me more time than was needed to implement it.
Here is the taggingtree
filter code for copy-pasting:
/*\
title: $:/core/modules/filters/taggingtree.js
type: application/javascript
module-type: filteroperator
Filter operator returning all tiddlers that are tagged with the selected tiddlers
as well as those tagged below in the tag hierarchy
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
code adapted from $:/core/modules/filters/tagging.js
*/
exports.taggingtree = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
// start the recursion for this title
getTdidlersRecursively(title,results,options);
});
return results;
};
function getTdidlersRecursively(title,results,options) {
// get tagging[] list at this level
var intermediate = options.wiki.getTiddlersWithTag(title),
t,p;
// remove any that are already in the results array to avoid loops
// code adapted from $tw.utils.pushTop
if(intermediate.length !== 0) {
if(results.length !== 0) {
if(results.length < intermediate.length) {
for(t=0; t<results.length; t++) {
p = intermediate.indexOf(results[t]);
if(p !== -1) {
intermediate.splice(p,1);
}
}
} else {
for(t=intermediate.length-1; t>=0; t--) {
p = results.indexOf(intermediate[t]);
if(p !== -1) {
intermediate.splice(t,1);
}
}
}
}
// add the remaining intermediate results and traverse the hierarchy further
$tw.utils.pushTop(results,intermediate);
intermediate.forEach(function(title) {
getTdidlersRecursively(title,results,options);
});
}
return;
}
})();
taggingtree.js.tid (1.7 KB)
Usage is basically identical to tagging[]
, except that it will generally yield more results. There is a loop filter to avoid infinite recursion.
Caveats:
- I’d rather have done this in wikitext. There is a related discussion on GG, and for a while I went with @Mark_S’ proposal for nested subfilters. That only works for a predefined hierarchy depth, though. Comparing with my comments then, my hierarchy depth has increased by at least 4 levels since that time, so that code must be updated regularly to keep up with my taxonomy mania.
Also, it is about 15 % faster than the nested subfilters approach (in a test which yielded ≈ 3,600 result tiddlers, usingcount[]
to avoid the DOM creation overhead when timing) and probably orders of magnitude faster thankin
. - I’m not a JS expert. The code above is mostly copy-pasted from other modules in TW. I’ve given credit in the code comments. I do not know in detail how some of it, e.g. the tiddler iterator
source
, works. If there are ways to improve the code or make it more conforming to TW standards, please let me know.
See also the preceding discussion here in the forum for why I don’t just use the kin
filter or a recursive macro (mostly speed issues), where @TW_Tones also proposed a macro solution.
Have a nice day
Yaisog