a-z tabs from custom author field

55 views
Skip to first unread message

Mark

unread,
Dec 24, 2007, 3:36:47 AM12/24/07
to TiddlyWiki
Assuming a custom field of "author" containing hundreds of author
names, is there a way to auto generate an A-Z list of tabs using Udo's
ForEachTiddlerPlugin?

The following works to list all the tiddler titles that start with
"A":

<<forEachTiddler
where
'tiddler.title.startsWith("A")'
>>

How can I adapt this to work with the custom field (author) instead of
tiddler titles?

And then, how to get to an A-Z set of tabs based on the author values?

Something to the effect of:

forEachTiddler
where
'store.getValue(tiddler,"author") startsWith A
then generate tab A
and so on to automatically create tabs A-Z from author field values

Thanks for any helpful hints.

FND

unread,
Dec 24, 2007, 8:32:33 AM12/24/07
to Tiddl...@googlegroups.com
> Assuming a custom field of "author" containing hundreds of author
> names, is there a way to auto generate an A-Z list of tabs

Using the ForEachTiddlerPlugin[1], you would use something like the
following for each individual tab:
---------------
<<forEachTiddler
where 'store.getValue(tiddler, "author") &&
store.getValue(tiddler, "author").substr(0, 1).toLowerCase() == "a"'
write '"* [[" + tiddler.title + "]]\n"'
>>
---------------
(The .toLowerCase() method for case-insensitive comparison is optional.)

In order to automatically generate that list for each letter of the
basic Latin alphabet, I've used the InlineTabsPlugin[2] and came up with
the following script (requires InlineJavascriptPlugin[3]):
---------------
<script>
var FETScriptPre = '<<forEachTiddler\n'
+ 'where [[store.getValue(tiddler, "author") && '
+ 'store.getValue(tiddler, "author").substr(0, 1).toLowerCase() == "'
var FETScriptPost = '"]]\n'
+ 'write \'"* [[" + tiddler.title + "]]\\n"\'\n'
+ '>>\n'
var c;
var output = "<tabs authorsIndex>\n";
for(var i = 0; i < 26; i++) {
c = String.fromCharCode(i + 97);
output += "<tab " + c + ">\n";
output += FETScriptPre + c + FETScriptPost;
output += "</tab>\n";
}
output += "</tabs>";
wikify(output, place);
</script>
---------------
It's not pretty (mostly due to the nested quotes of the FET macro call),
but it seems to work.

HTH.


-- F.


[1] http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin
[2] http://tw.lewcid.org/sandbox/#InlineTabsPlugin
[3] http://www.tiddlytools.com/#InlineJavascriptPlugin

wolfgang

unread,
Dec 24, 2007, 11:02:58 AM12/24/07
to TiddlyWiki
Nice script, F.

how would it would look like to make the tabs wrap - for being able to
put it into the SidebarTabs?

regards,

W.

FND

unread,
Dec 24, 2007, 12:04:41 PM12/24/07
to Tiddl...@googlegroups.com
> how would it would look like to make the tabs wrap

I'm not entirely sure why the tabs don't simply wrap by default (as far
as I can tell, they're just inline elements - so basically not much
different from regular text).
Nevertheless, try adding this to your StyleSheet:
.tabset {
overflow: auto;
}
.tab {
display: block;
float: left;
}

You could also have a vertical tab bar with the contents on the right:
.tabset {
float: left;
padding: 0;
}
.tabContents {
overflow: auto;
}
.tab {
display: block;
}

Neither of these things is heavily tested, so let me know if you run
into problems.


-- F.

Mark

unread,
Dec 24, 2007, 12:12:14 PM12/24/07
to TiddlyWiki
It works!

for all 1178 items (a list of master's theses)

I added this bit:

"+store.getValue(tiddler,"author")+" &ndash;

to the write statement so that the author values and a ndash are
included along with the titles:

<script>
var FETScriptPre = '<<forEachTiddler\n'
+ 'where [[store.getValue(tiddler, "author") && '
+ 'store.getValue(tiddler, "author").substr(0, 1).toLowerCase() ==
"'
var FETScriptPost = '"]]\n'
+ 'write \'"* "+store.getValue(tiddler,"author")+" &ndash; [[" +
tiddler.title + "]]\\n"\'\n'
+ '>>\n'
var c;
var output = "<tabs authorsIndex>\n";
for(var i = 0; i < 26; i++) {
c = String.fromCharCode(i + 97);
output += "<tab " + c + ">\n";
output += FETScriptPre + c + FETScriptPost;
output += "</tab>\n";
}

output += "</tabs>";
wikify(output, place);
</script>

Thanks for this beautiful (in my eyes) little piece of code!

It helps a lot.

mck

Mark

unread,
Dec 24, 2007, 12:17:27 PM12/24/07
to TiddlyWiki
That would work in general but for this use where I have included over
1100 items, I have hidden the sidebar to speed up the processing
time.

I'm trying to keep this as slim and fast loading as possible.

Thanks!

mck

FND

unread,
Dec 24, 2007, 12:23:09 PM12/24/07
to Tiddl...@googlegroups.com
> It works! [...] It helps a lot.

Glad I could help.

> Thanks for this beautiful (in my eyes) little piece of code!

It's not beautiful code at all to me.
For example, instead of embedding the FET macro calls, we could have
directly used the forEachTiddler() core function (since we're using
custom code, it's not suitable for non-tech-savvy users anyway).
In fact, that would probably have been much easier - why didn't I think
of that before?!
Well, maybe another time...


-- F.

wolfgang

unread,
Dec 24, 2007, 4:10:04 PM12/24/07
to TiddlyWiki
Hi everyone,

> Nevertheless, try adding this to your StyleSheet:
> .tabset {
> overflow: auto;
> }
> .tab {
> display: block;
> float: left;
> }

That did the trick. :-)

> For example, instead of embedding the FET macro calls, we could have
> directly used the forEachTiddler() core function (since we're using
> custom code, it's not suitable for non-tech-savvy users anyway).
> In fact, that would probably have been much easier - why didn't I think
> of that before?!

It it would have been possible to write the same code independent of
FET - that would indeed have been a good idea. But actually I've FET
on all my TWs installed. So it wouldn't be that much of a difference.
Also the dependence on InlineTabs and InlineJavascript would still
remain.

> That would work in general but for this use where I have included over
> 1100 items, I have hidden the sidebar to speed up the processing
> time.
>
> I'm trying to keep this as slim and fast loading as possible.

For me that was the surprising part of FND's script. If I include a 18
hundred tiddlers TiddlyWiki - and the Timeline or All tab open - a
tiddler 'done' usually takes me up to 20 seconds (compared to about 2,
if I close the tabs completely or use more/shadowed tab). With this
tab script open it doesn't take much longer than the 2 seconds too!

Regards,

W.

FND

unread,
Dec 24, 2007, 6:05:32 PM12/24/07
to Tiddl...@googlegroups.com
> If I include a 18 hundred tiddlers TiddlyWiki - and the Timeline or
> All tab open - a tiddler 'done' usually takes me up to 20 seconds [...]
> With this tab script open it doesn't take much longer than [...] 2 seconds

I'm not sure I understand that scenario, but the difference between
Timeline/All and these tabs is simply the amount of data that's being
rendered.

In fact, that's also the reason why embedded the FET macro call is
indeed required after all; the macro is only executed when it's being
rendered (i.e. when the respective tab is selected), so the tabs reduce
the processing effort to 1/26th (on average).

Of course I could say now that this fact had temporarily slipped my mind
when I was criticizing myself before - but that performance advantage is
really more of a conceptual accident; the reason I had used the FET
macro in the first place was because I hadn't yet thought about
automatically generating those tabs.


-- F.

Mark

unread,
Dec 25, 2007, 2:03:47 AM12/25/07
to TiddlyWiki

... the ugly duckling is actually a swan!

One ruffled feather remains:

Is there a way to make the tiddlers sort alphabetically within each
tab?

Here's to happy holidays!

Thanks again!

Mark

Mark

unread,
Dec 25, 2007, 4:15:36 AM12/25/07
to TiddlyWiki
Oops:

What I meant to say was:

Is there a way to make the tiddlers sort alphabetically [by author]
within each
tab?

Mark

FND

unread,
Dec 25, 2007, 4:48:32 AM12/25/07
to Tiddl...@googlegroups.com
> Is there a way to make the tiddlers sort alphabetically [by author]
> within each tab?

Use the FET macro's sortBy command:


---------------
<<forEachTiddler
where 'store.getValue(tiddler, "author") &&
store.getValue(tiddler, "author").substr(0, 1).toLowerCase() == "a"'

sortBy 'tiddler.fields["author"]'
write '"* " + tiddler.fields["author"] + " &ndash; "
+ "[[" + tiddler.title + "]]\n"'
>>
---------------
Note that instead of using store.getValue(), I've used tiddler.fields[]
for the sortBy and write arguments - that means that only the current
iteration's tiddler object is accessed there, instead of processing the
entire store again (another potential performance enhancement).

Our script should look like this then:


---------------
<script>
var FETScriptPre = '<<forEachTiddler\n'
+ 'where [[store.getValue(tiddler, "author") && '
+ 'store.getValue(tiddler, "author").substr(0, 1).toLowerCase() == "'
var FETScriptPost = '"]]\n'

+ 'sortBy \'tiddler.fields["author"]\'\n'
+ 'write \'"* " + tiddler.fields["author"] + " &ndash; " '
+ '+ "[[" + tiddler.title + "]]\\n"\'\n'


+ '>>\n'
var c;
var output = "<tabs authorsIndex>\n";
for(var i = 0; i < 26; i++) {
c = String.fromCharCode(i + 97);
output += "<tab " + c + ">\n";
output += FETScriptPre + c + FETScriptPost;
output += "</tab>\n";
}
output += "</tabs>";
wikify(output, place);
</script>
---------------

(All those nested quotes are driving me $#@%!)*

> ... the ugly duckling is actually a swan!

It's still an ugly duckling, but one with quick feet.
(Sort of the equivalent of Steffi Graf, I guess... )*


-- F.


* Yes, that's my Christmas mood at work right there...

Mark

unread,
Dec 25, 2007, 5:38:19 AM12/25/07
to TiddlyWiki
Thanks!

Works like a charm.

The little ugly duckling is putting on the ritz!

One last irksome detail:

Is it possible to change the a-z tab labels from lower case to upper
case (A-Z)?

Cheers!

Mark

FND

unread,
Dec 25, 2007, 5:49:11 AM12/25/07
to Tiddl...@googlegroups.com
> Is it possible to change the a-z tab labels from lower case to upper
> case (A-Z)?

Sure - just change the following lines (old/new adjacency pairs)


+ 'store.getValue(tiddler, "author").substr(0, 1).toLowerCase() == "'

+ 'store.getValue(tiddler, "author").substr(0, 1).toUpperCase() == "'


c = String.fromCharCode(i + 97);

c = String.fromCharCode(i + 65);

This then results in the following script:


---------------
<script>
var FETScriptPre = '<<forEachTiddler\n'
+ 'where [[store.getValue(tiddler, "author") && '

+ 'store.getValue(tiddler, "author").substr(0, 1).toUpperCase() == "'


var FETScriptPost = '"]]\n'
+ 'sortBy \'tiddler.fields["author"]\'\n'
+ 'write \'"* " + tiddler.fields["author"] + " &ndash; " '
+ '+ "[[" + tiddler.title + "]]\\n"\'\n'
+ '>>\n'
var c;
var output = "<tabs authorsIndex>\n";
for(var i = 0; i < 26; i++) {

c = String.fromCharCode(i + 65);


output += "<tab " + c + ">\n";
output += FETScriptPre + c + FETScriptPost;
output += "</tab>\n";
}
output += "</tabs>";
wikify(output, place);
</script>
---------------

HTH.


-- F.

Mark

unread,
Dec 25, 2007, 6:46:46 AM12/25/07
to TiddlyWiki
CSA!

Many Thanks!

mck

Michael.Tarnowski

unread,
Feb 1, 2008, 1:25:19 AM2/1/08
to TiddlyWiki
On basis of the ForEachTiddlerPlugin (Udo's:
http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin) and
NestedSlidersPlugin (Eric's: http://www.TiddlyTools.com/#NestedSlidersPluginInfo)
I wrote a tiddler to display a kind of A-Z tabs:

--- begin of code --
+++[A]
<<forEachTiddler where 'tiddler.title.startsWith("A") '
write '"\n[["+tiddler.title+"]]"'>>
===
...
...
<for all other letters in the alphabet>
--- end of code ---

My question is now how should I set up the code to OPEN all tiddlers
starting with the appropriate letter?
Cheers Michael

FND

unread,
Feb 1, 2008, 3:34:02 AM2/1/08
to Tiddl...@googlegroups.com
> how should I set up the code to OPEN all tiddlers
> starting with the appropriate letter?

For this you could use the OpenTiddlersMacro*, you could try the following:
---------------
<<openTiddlers
text:"click"
tiddlers:{{
var letter = "S";
var tiddlers = store.getTiddlers().map(function(t) {
return t.title;
});
var t = "";
for(var i = 0; i < tiddlers.length; i++) {
if(tiddlers[i].indexOf(letter) == 0)
t += "[[" + tiddlers[i] + "]] ";
}
t;
}}
>>
---------------

Of course this macro call could also be embedded into a script that
automatically generates this macro for each letter of the alphabet
(similar to what we did for Mark before), but that's gonna take some
more effort...


-- F.


* http://tinyurl.com/3xgg26
(http://tw.lewcid.org/svn/plugins/OpenTiddlersMacro/OpenTiddlersMacro.js)

wolfgang

unread,
Feb 1, 2008, 6:20:08 AM2/1/08
to TiddlyWiki
Hi everyone,

> Of course this macro call could also be embedded into a script that
> automatically generates this macro for each letter of the alphabet
> (similar to what we did for Mark before), but that's gonna take some
> more effort...

Meanwhile, to shorten the whole thing and to have less errors prone
code tiddlers, you could use tiddlers with parameters - by writing in
one tiddler with the title, for example, 'OpenAll':
__________

<<openTiddlers
text:"click"
tiddlers:{{
var letter = "$1";
var tiddlers = store.getTiddlers().map(function(t) {
return t.title;
});
var t = "";
for(var i = 0; i < tiddlers.length; i++) {
if(tiddlers[i].indexOf(letter) == 0)
t += "[[" + tiddlers[i] + "]] ";
}
t;
}}
>>
__________

And than for each letter of the alphabet accordingly:

<<tiddler OpenAll with: S>>

regards,

W.

wolfgang

unread,
Feb 1, 2008, 6:33:17 AM2/1/08
to TiddlyWiki
> On basis of the ForEachTiddlerPlugin (Udo's:http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin) and
> NestedSlidersPlugin (Eric's:http://www.TiddlyTools.com/#NestedSlidersPluginInfo)
> I wrote a tiddler to display a kind of A-Z tabs:
>
> --- begin of code --
> +++[A]
> <<forEachTiddler where 'tiddler.title.startsWith("A") '
> write '"\n[["+tiddler.title+"]]"'>>
> ===

take a look at the thread 'forEachTiddler question':

http://groups.google.com/group/TiddlyWiki/browse_thread/thread/545071eeab0ab54c/2c5ca42e31edb91a?lnk=gst&q=a-z#2c5ca42e31edb91a

there I came up with a similar to your solution with NestedSliders,
but instead used them together with DomTweaksPlugin in their deferred
variety. So that not all 26 ForEachTiddler call are automatically
processed whenever you open that tiddler - or even always - when you
place this in the SideBarTabs, as I did.

W.

http://www.tiddlytools.com/#DOMTweaksPlugin

FND

unread,
Feb 1, 2008, 6:41:36 AM2/1/08
to Tiddl...@googlegroups.com
> Meanwhile, to shorten the whole thing and to have less errors prone
> code tiddlers, you could use tiddlers with parameters

Clever solution, Wolfgang - I'd actually prefer that over a convoluted
FET macro call!
(quoting myself: "Duh! *facepalm* Why didn't I think of that... ")


-- F.

Reply all
Reply to author
Forward
0 new messages