Need feedback on a technique using a ListWidget with pairs of items from a filter

Hi everyone! I recently implemented something in my own wiki, and I wanted to share the solution, partly as a form “this is how I solved a problem”, but also to get feedback and see if there’s a better way to do it. The specific problems are:

  • Using <$list> to work with pairs of items from a filter, rather than individual items
  • “Escaping” tiddler lists from a tiddler to process those as individual items rather than “flattening” them into their individual entries

Background

I have my personal wiki set up to not update the browser URL with the permaview via the “Behaviour of the browser address bar when navigating to a tiddler” setting (I found that this made URLs from my wiki dominate address bar search results) - this works for me, but when I reload my wiki, I lose the list of open tiddlers. Now, I could click the “permaview” button, but that only works if I remember, which I often don’t :sweat_smile:

I happen to have a plugin I call “papertrail” that stores historical versions of tiddlers in the browser’s local storage, so I’ve been solving this problem by digging out the most recent value for $:/StoryList and manually altering the story list via the browser devtools. This works, but it’s kind of a pain - so I decided to write up a little UI in TiddlyWiki to get the job done.

Solution

For the UI, I wrote a little filter operator named papertrail that just extracts the 10 latest $:/StoryList entries from local storage, and yields element pairs for each entry. The first part of each pair is the timestamp for the entry, and the second part is the list field from parsing that entry.

(The fact that the second part of the pairs is a list complicates things, but I’ll get back to that after discussing my strategy for working on a list of pairs in general)

At this point, I wanted to use a <$list> widget to build up a table of entries - but <$list> can’t iterate over pairs of items from a filter (as far as I know). So, in order to iterate over pairs of items, I did this:

  • I used <$set name="entry_pairs" filter="[papertrail[]"> to slurp the filter results into a variable
  • I then used <$set name="entry_count" filter="[enlist:raw<entry_pairs>count[]]"> and <$list variable="n" filter="[range[1],<entry_count>,[2]]"> to iterate over indexes
  • And then I used <$set name="nPlus1" filter="[<n>add[1]]"> with [enlist:raw<entry_pairs>nth<n>] and {[enlist:raw<entry_pairs>nth<nPlus1>] to extract the contents of the list

So, Question #1: is this the best way to work on a the results of a filter in a pairwise fashion? It works fine for a small list like this one, but I imagine it could get quite slow for large lists!

Now, I mentioned this above, but the fact that the second part of each pair is a tiddler list complicates things, because enlist:raw will “flatten” those lists out! To get around this, I changed entry_pairs to <$set name="entry_pairs" filter="[papertrail[$:/StoryList]encodebase64[]]">, and then used decodebase64 within the <$list> body to work around that.

Question #2 - Is there a better approach to “escaping” tiddler lists within a filter?

Please let me know if this helps you out, or if you have ideas for how to improve it!

I’ll come back to your larger solution, but I’m puzzled by this. Why not just use the control panel to establish the storylist as your default set of tiddlers?

(If, like me, you have a web-facing version and also want particular author-facing behaviors, you can set up a script that runs on load and checks whether you’re in author-mode (logged in at tiddlyhost, or accessing over local file connection), and resets the storylist for the public as needed…)

I do suspect that whatever you’re doing with these list pairs is better done by simply having a regular list widget (reverse-sorted by modified field and limited to 10, say) and then being able to also display the modified date in the list view, within whatever context you need for viewing… but I haven’t looked deeply at your solution or what might justify making it so complex…

1 Like

For anyone who hasn’t discovered this trick yet, here’s the button that will do this for you:

That filter is [list[$:/StoryList]], in case you need it for other reasons.

And for more on this useful technique, see StartupActions.


@hoelzro, I think I’m also missing something. Do you really need access to multiple prior storylists, or just the most recent version (so that you can pick up where you left off)?

If you do need a history of sessions, so to speak, a DictionaryTiddler seems like a natural place to store this data, as they’re already designed to handle paired strings. I’d set the timestamp as the index and the corresponding title list as the value; this will let you use [[StorylistHistory]getindex<timestamp>enlist-input[]] to retrieve the list.

That’s a great question! The reason is because I have multiple tabs/windows across multiple machines viewing different story lists for my wiki, so the currently stored $:/StoryList on the server isn’t authoritative.

That’s a good idea - to make sure I understand you correctly, are you suggesting that I have a filter operator return something like the “papertrail keys” for the latest 10 entries, and then use other filter operators/macros/etc to extract the modified date/list/etc for a given entry?

I mostly need the most recent version, but I have multiple story lists across multiple tabs/windows/browsers, so being able to go back a little further in time is important.

That’s a really good point! I do think that a dictionary tiddler would be a more natural fit - I would just need to adapt my papertrail plugin to maintain that dictionary tiddler in addition to the local storage data (“in addition to” rather than “instead of”, because I originally wrote the plugin as a “belt and suspenders” approach to protecting myself from potential data loss if tiddler saving stopped working for whatever reason).

2 Likes