PageTurner Issues

When I first started with TW I needed a way to ‘turn pages’ going from one tiddler to the next. Someone on this list, I forget who, gave me a tiddler, PageTurner, which did that beautifully, code below.

<$list filter="[<currentTiddler>tag[Artworks]]">
<div style="float:right;">
   <$vars prev={{{ [tag[Artworks]sort[]before<currentTiddler>] }}}>
   <$vars next={{{ [tag[Artworks]sort[]after<currentTiddler>] }}}>
   <$reveal default=<<prev>> type="nomatch" text="">
   <$button tooltip=<<prev>>> {{$:/core/images/chevron-left}}
      <$action-sendmessage $message="tm-close-tiddler" param=<<currentTiddler>> />
      <$action-navigate $to=<<prev>>/>
   </$button>
   </$reveal>
   <$reveal default=<<next>> type="nomatch" text="">
   <$button tooltip=<<next>>> {{$:/core/images/chevron-right}}
      <$action-sendmessage $message="tm-close-tiddler" param=<<currentTiddler>> />
      <$action-navigate $to=<<next>>/>
   </$button>
   </$reveal>
   </$vars>
   </$vars>
</div>
</$list>

I now want to do something similar yet different. The problem is that the code works perfectly if I restrict the filters to all artworks.

But my requirement is for a subset of Artworks, for example, all artworks of a type or within a specific date range. I guess I could provide a number of PageTurner tiddlers, each handling a specific filter but I prefer generic solutions. I sort of need to provide my filter as a parameter to this code but can not see a way to do that. I would love it if I could store required filters on separate tiddlers and then use the contents of a tiddler to provide the filter statement to be interpreted at run time.

For example, have a tiddler PG1 with text of [<currentTiddler>object_type[Artist Books]] and have the filter code in PageTurner read something liked <$list filter=<<PG1>>

Each artwork tiddler has a field object_type which specifies the type of work that it is, so, Painting, Artist Book, Print, etc.

Can anyone shed some light on this for me?

bobj

3 Likes

I’m pretty certain that code came from me.

Here’s how to modify it to achieve your new goal (“provide my filter as a parameter”):

\procedure PageTurner(filterTiddler)
<$let filt={{{ [<filterTiddler>get[text]] }}}>
<$list filter="[<filt>!match[]then<currentTiddler>subfilter<filt>]">
<div style="float:right;">
   <$vars prev={{{ [subfilter<filt>sort[]before<currentTiddler>] }}}>
   <$vars next={{{ [subfilter<filt>sort[]after<currentTiddler>] }}}>
   <$reveal default=<<prev>> type="nomatch" text="">
   <$button tooltip=<<prev>>> {{$:/core/images/chevron-left}}
      <$action-sendmessage $message="tm-close-tiddler" param=<<currentTiddler>> />
      <$action-navigate $to=<<prev>>/>
   </$button>
   </$reveal>
   <$reveal default=<<next>> type="nomatch" text="">
   <$button tooltip=<<next>>> {{$:/core/images/chevron-right}}
      <$action-sendmessage $message="tm-close-tiddler" param=<<currentTiddler>> />
      <$action-navigate $to=<<next>>/>
   </$button>
   </$reveal>
   </$vars>
   </$vars>
</div>
</$list>
\end

Notes:

  • Start by enclosing the code within a \procedure definition, so that you can
    • pass a tiddler title as a parameter
    • invoke it with a simple <<PageTurner tiddlername>> syntax
  • Tag this tiddler with $:/tags/Global so the PageTurner procedure can be used in other tiddlers
  • Next, create a separate tiddler (e.g., “PG1”), containing: [object_type[Artist Books]]
    • Note that this filter does NOT include <currentTiddler>, which is automatically added as needed in the PageTurner procedure’s code
  • Lastly, where you were using your previous code, replace it with <<PageTurner PG1>>

Also, for your specific example of limiting the previous/next navigation to the current tiddler’s object-type, you could make these changes:

  • Instead of defining a global \procedure, just place this code into a tiddler tagged with $:/tags/ViewTemplate:
<$list filter="[<currentTiddler>get[object-type]]" variable=thistype>
<div style="float:right;">
   <$vars prev={{{ [all[]object-type<thistype>sort[]before<currentTiddler>] }}}>
   <$vars next={{{ [all[]object-type<thistype>sort[]after<currentTiddler>] }}}>
   <$reveal default=<<prev>> type="nomatch" text="">
   <$button tooltip=<<prev>>> {{$:/core/images/chevron-left}}
      <$action-sendmessage $message="tm-close-tiddler" param=<<currentTiddler>> />
      <$action-navigate $to=<<prev>>/>
   </$button>
   </$reveal>
   <$reveal default=<<next>> type="nomatch" text="">
   <$button tooltip=<<next>>> {{$:/core/images/chevron-right}}
      <$action-sendmessage $message="tm-close-tiddler" param=<<currentTiddler>> />
      <$action-navigate $to=<<next>>/>
   </$button>
   </$reveal>
   </$vars>
   </$vars>
</div>
</$list>

Notes:

  • The initial $list widget detects if the current tiddler has a non-blank object-type field. If it does, that field’s value is copied into the thistype variable. This filter also automatically limits the display of the content that follows to only those tiddlers that have an object-type field.
  • The calculation of prev and next then uses the <thistype> variable to find the previous/next tiddler that has the same object-type as the current tiddler.

enjoy,
-e

3 Likes

Fantastic @EricShulman . Fancy a knighthood?

If only it were in my power… :slight_smile:

Maybe this should be added to the TW documentation. It would be useful to others now and in to the future.

bobj

Indeed. Exemplary piece of wikitextmanshipTM (hereby coined by me!)

Here’s a more compact bit of coding for the object-type navigation:

\define close() <$action-sendmessage $message="tm-close-tiddler" param=<<currentTiddler>>/>

<$list filter="[<currentTiddler>get[object-type]]" variable=thistype>
<div style="float:right;">
   <$list filter="[all[]object-type<thistype>sort[]before<currentTiddler>]" variable="prev">
      <$button tooltip=<<prev>>>{{$:/core/images/chevron-left}}
         <<close>><$action-navigate $to=<<prev>>/>
      </$button>
   </$list>
   <$list filter="[all[]object-type<thistype>sort[]after<currentTiddler>]" variable="next">
      <$button tooltip=<<next>>>{{$:/core/images/chevron-right}}
         <<close>><$action-navigate $to=<<next>>/>
      </$button>
   </$list>
</div>
</$list>

Notes:

  • Define a <<close>> macro as an “abbreviation” for the tm-close-tiddler message.
  • Instead of using $vars with “filtered transclusion” syntax, use $list widgets with variable=...
  • The $list widgets also eliminate the need for separate $reveal widgets to omit the previous or next button when at the first or last tiddler in the sequence.

-e

2 Likes

@EricShulman why do I get the feeling that if I wait long enough you’ll provide a one word command to do all that :slight_smile:

Looking through your code, I realise that I’m a long way from your mastery of coding in TW. I also realised that many of the issues I face are because I do not understand how TW code works nor do I have the grasp of how to combine functions/operators/procedures/etc to achieve what I want. In other languages I code in, I do have that understanding and so coding in them is easier for me. I realise this is a time issue, I need to do more work in TW coding. However, the TW documentation does not really help, as I’ve noted before. The examples in the documentation are not real examples, they, for the most part, are trivial and are difficult to translate into a real scenario.

Anyway, I am learning off you all the time, so thank you again.

3 Likes

Coincidentally, I was fantasizing about building a solution very much like this recently! So I will use this as a point of departure. Thanks!

One related question — but from another angle:

How hard would it be to get the “page-turn” effect to animate in a way that looks more like a horizontal sliding?

Currently the combination of closing current tiddler and opening the next (or previous) one looks rather jumpy.

If we could get something like the @saqimtiaz Swiffy slider effect… (but without the need for an additional enclosing frame — or perhaps the enclosing frame is so thin as to be invisible?)… that would be user-interface gold!

Is this any closer to what you need? The catch with this style of sliding animation in Swiffy is that it requires that the slides are already rendered in the background, which could be slow on initial display for a large number of slides.

Wow, looks fantastic! For text-based tiddlers (my use case), or even for a small set of image-inclusive tiddlers, I think the background rendering would not cause delay.

The swiffy sliding effect would be especially intuitive on iOS and similar platforms… For desktop users, I may want to add some visual cues for the slide affordance — perhaps even a subtle button with increased alpha on hover — but this looks like exactly the kind of intuitive interaction I was hoping for.

The underlying Swiffy library has a configurator that lets you experiment with different settings, many of which have to do with navigation affordances. Most of the settings are applied by using the appropriate CSS class in the HTML.

You should be able to experiment there with display related options and then copy the classes used in their example and use the same classes in in TiddlyWiki. Further customization should be possible by defining your own CSS.

2 Likes

(and I would want the title bar (or a transcluded imitation of it) to slide over as well. But I think I can use your solution as a departure-point, and figure out the tweaks I need!)

1 Like

Just a follow-up: It turns out @saqimtiaz’s swiffy slider (linked above), in its very cool “drag/swipe to navigate” version, ends up disabling most click-interactions within the tiddlers it serves up (not all click interactions, curiously!). So even if I figured out how to minimized the “frame” tiddler and how to replicate title, subtitle etc. within the swiffy-slider-tiddler, this is not the solution I’d want to use for my purposes.

I’m curious whether anyone can figure out a navigation-button set that functions for story-river tiddlers and behaves just like other navigation buttons except bypassing the default story-river animations and instead invoking a sideways replacement animation (origin tiddler closed with slide-out-leftward, destination tiddler animated as entering from right — and vice versa with back button).

This way users would really feel the sense of navigating through a horizontal sequence, for the particular tiddlers using this solution.

I understand that this would be difficult if story-river animations are necessarily controlled by a central mechanism, open only to uniform global settings (i.e., story-view setting (zoomin vs pop vs classic), plus animation duration setting).

Anybody know whether this is the case?

It sounds like you want a new storyview that animates tiddler’s horizontally. Story views are written in JavaScript and each instance of a list widget can specify its own storyview. Given a sequence of tiddler’s A B C and D, you would also need to decide if navigating via links from C to D and C to A should have the same animation or if the position in the sequence should be reflected in the animation (direction and 2 steps instead of 1).

Is this meant to be a replacement for story river or in addition to? Where would you want to open tiddler’s that are linked to but not a part of the sequence.

With regards to Swiffy, if you are able to provide an example where some of the click interaction is disabled, that would be helpful. The selective disabling of only some click events sounds quite surprising.

@Springer I suggest we move these last few posts to their own thread