How to open the tiddler just before the current one in the history?

Is there an option to do an ‘or’ between operators? Then I’d do or[is[tiddler] is[draft] is[shadow]]

I ended up creating a ‘tabbed’ filter operator. Works OK, except for the use case I mentioned. That is, if I’m on a ‘foo’ tiddler and start editing, then the tiddler before the current one is ‘foo’ (current one is ‘draft of foo’. Need to figure out how to filter out tiddlers that have an open draft… I guess the best is if the operator can use the story list to find only tiddlers that are open.

Ended up creating an ‘instory’ filter operator. Here it is:

/*\
title: $:/customization/tabbed.js
type: application/javascript
module-type: filteroperator

Filter function for [instory[]]

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
	
var DEFAULT_STORY_TITLE = "$:/StoryList";


/*
Export our filter function
*/
exports.instory = function(source,operator,options) {
	var currStoryList = $tw.wiki.getTiddlerList(DEFAULT_STORY_TITLE);
	var storyFilter = $tw.utils.stringifyList(currStoryList);	
	var storyList = $tw.wiki.filterTiddlers(storyFilter)
	
	var results = [];
	if(operator.prefix === "!") {
		source(function(tiddler,title) {
			if (!storyList.includes(title)) {
				results.push(title);
			}
		});
	} else {
		source(function(tiddler,title) {
			if (storyList.includes(title)) {
				results.push(title);
			}
			
		});
	}
	return results;
};

})();

And while I’m at it, here’s a filter to get the history titles directly

/*\
title: $:/customization/history.js
type: application/javascript
module-type: filteroperator

Filter function for [history[]]

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
	
var DEFAULT_HISTORY_TITLE = "$:/HistoryList";


/*
Export our filter function
*/
exports.history = function(source,operator,options) {
	var historyList = options.wiki.getTiddlerDataCached(DEFAULT_HISTORY_TITLE,[])
	
	return historyList.map(item => item.title);
};

})();
2 Likes

The filter to get the history titles directly is a very good idea.

For the rest, below are some ideas that might be helpful:

Only retain titles that are real tiddlers or shadow tiddlers:

\define removeNonExistentTiddlers() [<currentTiddler>is[tiddler]then[yes]] [<currentTiddler>is[shadow]then[yes]]

[<history>filter<removeNonExistentTiddlers>]

Extending the above to only keep the titles that are in the story list:

\define removeNonExistentTiddlers() [<currentTiddler>is[tiddler]then[yes]] [<currentTiddler>is[shadow]then[yes]]

[<history>filter<removeNonExistentTiddlers>] :intersection[list[$:/StoryList]]

Note that it might be possible to replace the hardcoded $:/StoryList with the variable tv-story-list. Also you may not need to check if the title is a real or shadow tiddler if you only want titles that are in the story.

1 Like

UPDATE: Turns out that there are a few quirks to work around, so the code below will not work reliably. See my next post for a better solution.

Another approach that I have used successfully ist to order the Story List by the (reverse) History List – this way you’ll get a list of the open tiddlers, but sorted by their last viewed order.
I use it in a modified “Close” button in zoomin view (closing a tiddler shows the previously viewed open tiddler).
The code is rather straightforward:

\define reverse-history-list-filter() [<tv-history-list>get[text]splitregexp[\n]reverse[]unique[]trim[]removeprefix["title": "]removesuffix["]search-replace:g[\"],["]is[tiddler]]

<$set name="reverseHistoryList" filter=<<reverse-history-list-filter>> >
	<$let previousItem={{{ [list<tv-story-list>sortby<reverseHistoryList>nth[2]] }}}>
		<$action-navigate $to=<<previousItem>> />
	</$let>
</$set>

The parsing is a bit different from above solutions. It’s important to have reverse[] precede unique[], because unique[] will keep the first instance it finds and ignores all subsequent ones.
The search-replace[] is for cases where there’s a quotation mark in the title, which will get escaped (") in the history list.
If you wanted to suppress drafts, you’d ideally do it in the $let filter.
Have a nice day
Yaisog

PS: The is[tiddler] check is actually unnecessary here, because the history is only used for sorting a list of open and existing tiddlers. However, I use the same filter in a “History” button showing the last 30 opened tiddlers, where I do have to check, because of renames and deletions:

<$button popup=<<qualify "$:/state/popup/history">> class="tc-btn-invisible mwi-history-button" tooltip="Show tiddler history">
	{{$:/mwi/images/history}}
</$button>
<$reveal type="popup" state=<<qualify "$:/state/popup/history">> position="belowleft">
  <div class="tc-drop-down" >
	<h2 class="mwi-history-title">Tiddler-History</h2>
	<ol class="tc-toc">
	  <$list filter="[subfilter<reverse-history-list-filter>!is[draft]butfirst[]limit[30]]">
		<li>
		  <$link>
			<$let fieldName={{{ [all[current]is[system]then[title]] ~[all[current]has[caption]then[caption]else[title]] }}}>
			  <$view field=<<fieldName>> />
			</$let>
		  </$link>
		</li>
	  </$list>
	</ol>
  </div>
</$reveal>

PPS: With @Ittayd’s history[] filter, I guess this could be shortened to:

[history[]reverse[]unique[]search-replace:g[\"],["]]

so I’ll likely adopt that filter into my TW. For maximum flexibility I reckon it should evaluate <tv-history-list> instead of hard-coding the history tiddler title, though.
Not sure about the search-replace still being necessary, need to check.

2 Likes

I discovered some quirks that made the code in the previous post unreliable. Also, don’t parse the $:/HistoryList with WikiText filters, but use @Ittayd’s history[] filter above. I did change a line in the filter code to be able to pass an alternative history tiddler:

var historyTiddler = (operator.operand || "$:/HistoryList");
var historyList = options.wiki.getTiddlerDataCached(historyTiddler,[])

The code segment for the Close button becomes

<$set name="historyList" filter="[history<tv-history-list>reverse[]unique[]reverse[]]" >
	<$let previousItem={{{ [list<tv-story-list>sortby<historyList>reverse[]nth[2]] }}}>
		<$action-navigate $to=<<previousItem>> />
	</$let>
</$set>

The filter for historyList contains two reverse[] operators, because unique[] keeps only the first occurence, but we need each last one. Also, the sort-list needs to be in forward order, because sortby[] puts items that are not on this list up front. So after the then following reverse[] in the previousItem filter, they will be at the back AND the list will be sorted in reverse chronological order as we want it.

The list for the history button is also more straightforward with the history[] filter:

<$list filter="[history[]reverse[]unique[]is[tiddler]!is[draft]butfirst[]limit[30]]">

And there is no longer a need for the reverse-history-list-filter() definition.
Have a nice day
Yaisog

@Yaisog thanks for the follow up post.

I discovered

also, in my own wikitext parsing, but some of them may affect the history operator as well, but I have not looked closely at it yet. However I have uncovered the following;

The history list is added to at navigation or editing of a tiddler, so without targeted filtering, it will not only list both the tiddler AND its draft, but also the titles of now deleted or titles prior to a rename, ie the original title.

This does confound the use of history in this way but it also promises the possibility of some interesting functionality that may arise from this, especially if the history record was modified to include additional information. I could see this being done to reduce the potential problems I identified however once done, could then go one to do other interesting things such as I speculate now;

  • Ability to enable a rename to be reversed.
  • gather activity statistics from or in addition to the history

I have also speculated about keeping the history list across wiki loads, even a separate “Full History”, or in a single session declaring a new “historical Epoch”. For example one history for each project and more.

TiddlyWIki is always stimulating our imaginations.