Using <<forEachTiddler>> to list commonly tagged Tiddlers

10 views
Skip to first unread message

Matthew Horton

unread,
May 20, 2008, 12:03:24 AM5/20/08
to TiddlyWiki
Hello all:

I am using the following code to create "See also" lists on tiddlers
tagged the same way:

<<forEachTiddler
where 'tiddler != context.viewerTiddler &&
tiddler.tags.sort().join("]]") ==
context.viewerTiddler.tags.sort().join("]]")'
>>

My application is a glossary of terms for a class I teach. The macro
returns all terms tagged the same way as the term being viewed.
However, I also have a toggletag ("review") designed to mark terms
that the students need to review more. I would like the "see also"
list to be unaffected by this additional tag.

Is there a way to check for tag similarity while ignoring certain
tags?

I know how to overcome this problem by coding each tiddler
individually, but I wanted to minimize text and make it all work in a
single macro call in my viewtemplate, like this:

<div macro="showWhen tiddler.tags.contains('term')"><br>Related
terms:<div macro="tiddler SeeAlsoCode"></div></div>

Another way to describe what I want to do is this: list tiddlers that
have some tags in common but not necessarily all. I appreciate all
help.

Thanks much,

Matthew Horton

Robert Mark Bram

unread,
May 20, 2008, 8:07:30 PM5/20/08
to TiddlyWiki
Hi Matthew,

> Another way to describe what I want to do is this: list tiddlers that
> have some tags in common but not necessarily all. I appreciate all
> help.

Would this be covered by the http://mptw.tiddlyspot.com/#TagglyTaggingPlugin
used in MPTW?

Where for each tag attached to a tiddler, you get a button with a drop
down list of other tiddlers matching that tag?

Rob
:)

Matthew Horton

unread,
May 21, 2008, 12:39:36 AM5/21/08
to TiddlyWiki
Rob,

Thanks for your response. Actually, I am already using MPTW for this
particular tiddler (and others), but the task before me is to make a
list of tiddlers outside of the drop-down list and make it display in
the tiddler itself. The reason for my difficulty is that I want to
write a script that will do this job for any tiddler to avoid having
to manually code it in each one.

Please take a look at http://filmterms.tiddlyspot.com/#set for an
example. In the toolbar, you'll see a toggle box labeled "need
review"; if you click it, the "related terms" below the definition
disappear because the "review" tag has been added and the tiddler now
has a unique set of tags. I want to figure out how to make the script
that produces that "Related Terms" list ignore the addition of the
"review" tag.

This might all be a pipe dream, but I suspect anything is possible
with TW.

Thanks for you help,

Matthew

On May 20, 8:07 pm, Robert Mark Bram <robertmarkb...@gmail.com> wrote:
> Hi Matthew,
>
> > Another way to describe what I want to do is this: list tiddlers that
> > have some tags in common but not necessarily all. I appreciate all
> > help.
>
> Would this be covered by thehttp://mptw.tiddlyspot.com/#TagglyTaggingPlugin

FND

unread,
May 21, 2008, 2:47:22 AM5/21/08
to Tiddl...@googlegroups.com
> Please take a look at http://filmterms.tiddlyspot.com/#set for an
> example.

Ahh, that makes it much clearer, and easier to find a solution.

> I want to figure out how to make the script
> that produces that "Related Terms" list ignore the addition of the
> "review" tag.

Try this:
---------------


<<forEachTiddler
where 'tiddler != context.viewerTiddler &&

tiddler.tags.sort().join().replace("review", "").replace(",,",
",") == context.viewerTiddler.tags.sort().join().replace("review",
"").replace(",,", ",")'
>>
---------------
Mirrored here without the mangled line breaks:
http://tiddlywiki.pastebin.com/f74ea229a

It's a bit hacky, but should work fine.
Also note that I'm replacing the "review" tag on both ends there - not
sure whether that's what you want.

HTH.


-- F.

Matthew Horton

unread,
May 21, 2008, 9:11:39 AM5/21/08
to TiddlyWiki
It works. Thanks so much.

Would you mind explaining the replace() function to me? It does not
look like an array function, especially when you can string them
together like that.
Also, are the comma replacements because join() by default comma
delimits? Can you join by "nothing"?
If join() is applied, is the array no longer an array, just an array
with one value, or a simple string?

Thanks again for you your help,

Matthew

p.s. I did manage to fix the problem by writing a new script from
scratch last night. Here it is in case you are interested:

http://tiddlywiki.pastebin.com/m6331dd4c


On May 21, 2:47 am, FND <F...@gmx.net> wrote:
> > Please take a look athttp://filmterms.tiddlyspot.com/#setfor an

FND

unread,
May 21, 2008, 9:45:08 AM5/21/08
to Tiddl...@googlegroups.com
> Would you mind explaining the replace() function to me?

I'll break it down for you (including the obvious parts, for posterity):

0. x = tiddler; OR x = context.viewerTiddler;
select the respective tiddler

1. x = x.tags;
retrieve the respective tiddler's tags (array)

2. x.sort();
sort the tags array

3. x = x.join();
convert the array to a string, joining individual items with a separator
(default is a comma)

4. x = x.replace("review", "");
replace occurrences of "review" with an empty string (essentially
removing "review")

5. x = x.replace(",,", ",");
replace double commas (potential remnants from removing the "review"
bit) with a single comma
Alternatively, we could remove ",review" (or "review,") in step #4, but
that's not entirely safe because the review tag might occur at the
beginning or the end of the tag string (e.g. "review,ztag" vs.
"atag,review").

> Also, are the comma replacements because join() by default comma
> delimits? Can you join by "nothing"?

Yes, you could do array.join("") - but that's not a good idea here.

> I did manage to fix the problem by writing a new script from
> scratch last night.

I'll take a look later.


-- F.

Matthew Horton

unread,
May 21, 2008, 1:56:14 PM5/21/08
to TiddlyWiki
I appreciate the time you're taking to help me see how it works . . .
I hadn't thought of manipulating the string before, only the array.

>Yes, you could do array.join("") - but that's not a good idea here.
I tried an empty joiner and it worked; what bad things could happen or
might have happened?
Is it to avoid problems with unforeseen overlap between tags?

It also occurred to me that using commas (or any character) to
separate might end up yielding unequal strings. For instance, if one
string has "review" at the end and the other never had "review" in its
string in the first place (which is exactly the situation I am trying
to account for), we would get the following two strings after the
replace call:

"tag1,tag2" becomes "tag1,tag2"
"tag1,tag2,review" becomes "tag1,tag2,"

or if "review" were at the beginning:

"tag1,tag2" becomes "tag1,tag2"
"review,tag1,tag2" becomes ",tag1,tag2"

Replacing ",," with "," would not get rid of that first or last comma
because there would never be a double comma at the beginning or end of
a join() string . . . I think.

Am I off track here?

I am also curious whether you think it would be worthwhile to create a
macro for this function so that users could specify which tag(s) to
ignore in this kind of match? I hunted around for this pretty
extensively and did not find it, so I might be only one who needs it.

Thanks again,

Matthew

FND

unread,
May 21, 2008, 2:53:19 PM5/21/08
to Tiddl...@googlegroups.com
> I tried an empty joiner and it worked; what bad things could happen or
> might have happened?
> Is it to avoid problems with unforeseen overlap between tags?

Exactly - imagine you have the following tags "foo", "bar", "view", "re"
and "zab". After sorting and joining with an empty string, that would
turn into "foobarreviewzab", with tags #3 and #4 disappearing in the
next step.

> It also occurred to me that using commas (or any character) to
> separate might end up yielding unequal strings.

Indeed - good catch!
Let's try a regular expression then:


---------------
<<forEachTiddler
where 'tiddler != context.viewerTiddler &&

tiddler.tags.sort().join().replace(/^review,|,review/, "")) ==
context.viewerTiddler.tags.sort().join().replace(/^review,|,review/, ""));'
>>
---------------
This also combines steps 4 and 5.

> I am also curious whether you think it would be worthwhile to create a
> macro for this function so that users could specify which tag(s) to
> ignore in this kind of match? I hunted around for this pretty
> extensively and did not find it, so I might be only one who needs it.

I currently don't see a lot of demand for this - but I could look into
it if there's real interest (would require a slightly different
approach, i.e. some more time/effort).


-- F.

Matthew Horton

unread,
May 21, 2008, 7:19:36 PM5/21/08
to TiddlyWiki
That's perfect, thanks.

Simon Baird

unread,
May 21, 2008, 11:52:57 PM5/21/08
to Tiddl...@googlegroups.com
is containsAll any help? eg:

tiddler1.tags.containsAll(tiddler2.tags) && tiddler2.tags.containsAll(tiddler1.tags)

(I didn't follow this thread closely so ymmv...)
--
simon...@gmail.com

FND

unread,
May 22, 2008, 3:26:29 AM5/22/08
to Tiddl...@googlegroups.com
> is containsAll any help?

I'm not sure, but I think Matthew needs exact matches. For example:
tags1 = ["foo", "bar"];
tags2 = ["foo", "bar", "baz"];
var match = tags2.containsAll(tags1);
Here "match" will return TRUE - but I think it's meant to be FALSE in
that case.


-- F.

Reply all
Reply to author
Forward
0 new messages