There has been one or the other discussion about how to implement breadcrumb navigation here on Talk, e.g. Can Hierarchical Navigation Benefit TW Documentation?. What has been missing (I think) is, how to find the “right” path. Since the hierarchy is tag-based and each tiddler can have multiple tags, there will be multiple paths to one or more top-level tiddlers.
As an exercise, I tried to find a recursive method to find all possible paths for a given tiddler, and then sort them by length. Usually, the “right” one would be shortest one, I guess, or maybe the one that contains the most open tiddlers. Maybe we want to show the others paths in a tooltip.
Here’s what I came up with:
Tiddlywiki.com uses some tags that don’t exist as tiddlers and thus cannot have tags themselves and therefore no upwards hierarchy. To exclude these, we simply need to add a is[tiddler]
in the right place, though.
There is no true check for circular references, but a configurable counter that currently stops after 10 steps.
To play around with it, simply copy-paste this WikiText into a new tiddler on tiddlywiki.com and select any doc tiddler from the dropdown.
\define separator() »»
\define max-depth() 10
\function .escape-separator() [search-replace:g:regexp[»],[-»]]
\function .unescape-separator() [search-replace:g:regexp[-»],[»]]
\function .check-length() [all[current]split<separator>count[]compare:number:lteq<max-depth>then<currentTiddler>]
\function .get-step-inner() [all[current].check-length[]split<separator>last[]tags[]!is[system].escape-separator[]addprefix<separator>addprefix<currentTiddler>.get-step[]] :else[all[]]
\function .get-step() [all[]] :map:flat[<currentTiddler>.get-step-inner[]]
<$select tiddler=<<qualify '$:/temp/breadcrumbs-demo'>> default=<<currentTiddler>> >
<$list filter='[all[tiddlers]!is[system]sort[title]]'>
<option value=<<currentTiddler>>>
<$view field='title'/>
</option>
</$list>
</$select>
<$let start={{{ [<qualify '$:/temp/breadcrumbs-demo'>get[text].escape-separator[]] }}}
paths={{{ [<start>.get-step[]] :sort[split<separator>count[]] +[format:titlelist[]join[ ]] }}}>
<$let shortestPath={{{ [enlist<paths>first[]] }}} >
{{$:/core/images/home-button}} →
<$list filter="[<shortestPath>split<separator>.unescape-separator[]reverse[]butlast[]]" variable="node" join=" → ">
<$link to=<<node>> />
</$list>
</$let>
<br>
<% if [enlist<paths>count[]compare:number:gt[1]] %>
<br>
Alternative paths:<br>
<ul>
<$list filter="[enlist<paths>butfirst[]]" variable="path">
<li>
{{$:/core/images/home-button}} →
<$list filter="[<path>split<separator>.unescape-separator[]reverse[]butlast[]]" variable="node" join=" → ">
<$link to=<<node>> />
</$list>
</li>
</$list>
</ul>
<% endif %>
</$let>
The choice of the “right” path is all yours. Choose wisely!