Would counter-even and counter-odd for <$list> be useful to others?

When trying to create a certain zig-zag look1, I managed it with this pattern:

<table class="signs">
<$list filter="[tag[Sign]]" counter="counter">
<tr>
  <$list filter="[<counter>remainder[2]match[1]]" variable="_"><<sign-link>></$list>
  <!--           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        -->
  <td class="meta"><!-- ... more here ... --></td>
  <$list filter="[<counter>remainder[2]!match[1]]" variable="_"><<sign-link>></$list>
  <!--           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^       -->
</tr>
</$list>
</table>

This simply adds certain content as either the first or second cell in a table, and the other content as the second or the first. (Perhaps that would be better as match[0] instead of !match[1].)

Those highlighted sections are certainly not horrible. But it made me want to have counter-even and counter-odd similar to counter-first and counter-last. I could also see something similar to CSS’s nth-child, with something like counter-nth(5n+1)

That would turn the above into:

  <$list filter="[<counter-odd>]"  variable="_"><<sign-link>></$list>
  <!--           ^^^^^^^^^^^^^^^         -->
  <td class="meta"><!-- ... more here ... --></td>
  <$list filter="[<counter-even>]" variable="_"><<sign-link>></$list>
  <!--           ^^^^^^^^^^^^^^^^        -->

My question is whether others would find this useful? Although I have one minor contribution to TW, this would be the first substantive one I might create. I won’t bother bringing it up in GitHub if I’m the only one who sees it as useful. As I said, the above isn’t bad, but this would feel cleaner. Have I missed a built-in version of this?

I recognize that the counter can be a drag on performance, but "The best advice is only to use it when it is really necessary: to obtain a numeric index, or to detect the first or last entries in the list." (frrom #ListWidget). And this would seem to be an obvious extension to it.

So, is this something you would use?


1What I’m going for is the following zig-zag pattern:

You can see the fairly minimal code that achieved it by dragging zigazg.json (1.7 MB) to an empty wiki, and loading the tiddler Sign. (The CSS is in styles/main, and it involves what is probably an abuse of direction: rtl;; I’ll clean that up later.)

Without diving into details: isn’t it fairly easy to make css treat even and odd (and any other nth-child pattern) differently?

Perhaps because each item is itself so complex, a css solution doesn’t make sense for you here?

Yes, but only to some extent. My abuse of direction: rtl is the result of trying to (mis?)-use that property to choose which cell in a table row was rendered on the left or right. I may well have missed the correct way to do it. But when I successfully used the technique above without removing this CSS rule, it by happy coincidence flowed the text in the explanatory cell toward the image, for a nice look. All I had to do was remove the bullet points and I was quite pleased. I’ll still probably revisit this to do it with more appropriate tools, though.

In general, however, if you want to do something more serious on odd/even rows – or on every fifth row – like including additional content or using a whole new template, CSS is not going to help you much.

If you’re willing to use a grid container in place of a table, you can specify the column(s) to use for each defined class.

I have encountered this issue before, though, so I can see the value in an even/odd counter variable!

1 Like

Spontaneously: no. I reality it is not possible to know but I guess the chances for it increases now that you’ve planted a seed. But I don’t see any direct need or use for it. Thanks for asking though.

I’m certainly not wedded to a table. But while I have used css-grid (and flexbox), I haven’t seen that behavior. It sounds useful, and I’ll have to check it out.

Thank you!

And thanks for your reply! I won’t look at this very soon, but it’s great to know whether or not it would seem useful, for the day I could get to it!

It can help a lot because nth is not only odd and even and you can do CSS calc.

  • Would consider it to achieve the zig zag layout but not otherwise, because I do not need refer to another code pattern to do an odd even, and other “index” code patterns.

Here are some powerful examples that work on tiddlywiki.com

<$list filter="[tag[TableOfContents]]" counter=item>
   <$let nth.item={{{ [<item>remainder[3]] }}}>
      <<nth.item>> <$link/><br>
   </$let>
</$list>
  • Just change the 3 as needed
  • In the above you could add or subtract something in the “nth.item” to set the index the way you want.
  • I have also applied a little trick by naming the variable to include a period . because when I refer to it as <<nth.item>> it returns text only, a feature of “functions”.

Now once you have this nth.item you can do what you desire with it, such as;

<$list filter="[tag[TableOfContents]]" counter=item>
   <$let nth.item={{{ [<item>remainder[2]] }}}>
      <$list filter="[<nth.item>match[0]]" variable=~>
      <<nth.item>> <$link/><br>
      </$list>
      <$list filter="[<nth.item>match[1]]" variable=~>
      <<nth.item>> <$link/><br>
      </$list>
   </$let>
</$list>

In the above you can change the way you want each nth.item to look like within the list widgets, you could also use the template parameter to transclude a different list item template. For example;

<$list filter="[tag[TableOfContents]]" counter=item>
   <$let nth.item={{{ [<item>remainder[2]] }}} template={{{ [[$:/listitem/template/]addsuffix<nth.item>] }}}>
       <$transclude tiddler=<<template>>/> <<template>>
   </$let>
</$list>
  • Transcludes the list item templates $:/listitem/template/0 and $:/listitem/template/1 in which you can alter the layout.

But you can also just call a procedure/macro as follows;

\procedure nth-macro-0() <<item>>. <$link/>
\procedure nth-macro-1()  __<<item>>. <$link/>__
<$list filter="[tag[TableOfContents]]" counter=item>
   <$let nth.item={{{ [<item>remainder[2]] }}} macro={{{ [[nth-macro-]addsuffix<nth.item>] }}}>
       <$transclude $variable=<<macro>>/><br>
   </$let>
</$list>

Note the context of the question. I’m a huge fan of using CSS to control as much as I can. My point was that wikitext is much more powerful; you can do much more with it than you can with just CSS, and nth-child will only take you so far.

I’m thinking of this simply as syntactic sugar. It certainly wouldn’t add any capabilities, as you demonstrate. But it might turn this:

<$list filter="[tag[TableOfContents]]" counter=item>
   <$let nth.item={{{ [<item>remainder[3]] }}}>
      <$list filter="[<nth.item>match[1]]" variable=~>
        <div style="background-color: #ff9"><h2><$link/> (<$view field=modified format=date template="DDD,  YYYY-0MM-0DD" />)</h2></div>
      </$list>
      <$list filter="[<nth.item>!match[1]]" variable=~>
        <$link/><br>
      </$list>
   </$let>
</$list>

into the arguable simpler this:

<$list filter="[tag[TableOfContents]]" counter=item>
  <$list filter="[<item-nth(3)>match[1]]" variable=~>
    <div style="background-color: #ff9"><h2><$link/> (<$view field=modified format=date template="DDD,  YYYY-0MM-0DD" />)</h2></div>
  </$list>
  <$list filter="[<item-nth(3)>!match[1]]" variable=~>
    <$link/><br>
  </$list>
</$list>
  • I do too and agree
  • This is fine if it is a binary question. My approach is possibly better for any nth value, especialy the transclusions/template or macro versions.
  • In you simpler version is it incorrect that it tests for nth(3) but only has two outcomes?

@Scott_Sauyet I appreciate what you are trying to do but if we lay out the purpose or objective to achive it I think there are “native tiddlywiki script” ways to achieve it. In other words, your work points to some code patterns rather than the need for a new feature. This is especially the case since 5.3.x which as a community we are yet to work through fully.

I believe I can easily rewrite your <item-nth(3)> as a function, or provide other ways to use the following;

For example

  • counter even is [<item>remainder[2]match[1]
  • counter odd is [<item>remainder[2]match[0]
  • counter first is 1
  • counter last is filter +[count[]]
  • counter nth 5n+1 ? [<item>remainder[5]add[1]match[n] ?

I discovered recently the [[N]remainder[Y]] filter is the mathematical equivalent of ‘‘N modulo Y’’, its great for cyclic processes like hours in the day, degrees in a circle an this use case the nth.

  • Well worth investigating.

Consider a rewrite of my call a procedure macro

\function odd-even() [<item>remainder[2]]
\function odd-even-proc() [<odd-even>match[0]then[odd]else[even]]

<!-- the following is what to do on odd or even -->
\procedure odd() <<item>>. <$link/><br>
\procedure even()  __<<item>>. <$link/>__<br>

<$list filter="[tag[TableOfContents]]" counter=item>
       <$transclude $variable=<<odd-even-proc>>/>
</$list>
  • note in the above although solving this specifc problem the functions and procedures are reusable and redefinable to override locally if desired.
  • You could have an odd-even-transclude as well.

In closing

The above code pattern could also be incorporated in a custom widget, in which you have a <$fill $name=odd> and <$fill $name=even>.

  • I will post a widget solution shortly

Yes, and I shouldn’t post when I’m tired. This should have read something more like this:

<$list filter="[tag[TableOfContents]]" counter=item>
  <$list filter="[<item-nth(3n + 1)>match[yes]]" variable=~>
    <div style="background-color: #ff9"><h2><$link/> (<$view field=modified format=date template="DDD,  YYYY-0MM-0DD" />)</h2></div>
  </$list>
  <$list filter="[<item-nth(3n + 1)>!match[yes]]" variable=~>
    <$link/><br>
  </$list>
</$list>

So if you wanted different handling for multiple scenarios, you would just write it like this:

<$list filter="[tag[TableOfContents]]" counter=item>
  <$list filter="[<item-nth(3n+1)>match[yes]]" variable=~>@@background:#ff9;<$link/> (1)<br/>@@</$list>
  <$list filter="[<item-nth(3n+2)>match[yes]]" variable=~>@@background:#f9f;<$link/> (2)<br/>@@</$list>
  <$list filter="[<item-nth(3n)>match(yes)]" variable=~>@@background:#9ff;<$link/> (3)<br/>@@</$list>
</$list>

That’s still simple in your alternative pattern. But now let’s say we want to start this highlighting only after the fifth element, and it would become:

<$list filter="[tag[TableOfContents]]" counter=item>
    <$list filter="[<item-nth(3n-4>match[yes]]" variable=~>@@background:#ff9;<$link/> (1)<br/>@@</$list>
    <$list filter="[<item-nth(3n-3)>match[yes]]" variable=~>@@background:#f9f;<$link/> (2)<br/>@@</$list>
    <$list filter="[<item-nth(3n-5)>match[yes]]" variable=~>@@background:#9ff;<$link/> (3)<br/>@@</$list>
</$list>

And that starts to become nicer than using such patterns. Without the additional markup per branch, as @springer pointed out, this version could be handled fine just using CSS. The only goal here would be to extend that CSS notion to TW markup.

I’m certainly not suggesting that this is revolutionary. It is simple syntactic sugar, adding no functionality but making it easier to read and to understand. Very much like <counter-first> and <counter-last>. We could do without those using fairly simple patterns, but they offer nicer user ergonomics.

Though I would want this mostly for even / odd, the An + B syntax concisely captures a number of useful patterns in a consistent fashion. I don’t want to argue for it too strenuously. I’m not even 100% certain I want it; and it may well not be worth the clutter in TW’s offerings. But it would allow us to concisely capture TW equivalents to most of these examples:

Examples from MDN’s nth-child

  • tr:nth-child(odd) or tr:nth-child(2n+1)

    Represents the odd rows of an HTML table: 1, 3, 5, etc.

  • tr:nth-child(even) or tr:nth-child(2n)

    Represents the even rows of an HTML table: 2, 4, 6, etc.

  • :nth-child(7)

    Represents the seventh element.

  • :nth-child(5n)

    Represents elements 5 [=5×1], 10 [=5×2], 15 [=5×3], etc. The first one to be returned as a result of the formula is 0 [=5x0], resulting in a no-match, since the elements are indexed from 1, whereas n starts from 0. This may seem weird at first, but it makes more sense when the B part of the formula is >0, like in the next example.

  • :nth-child(n+7)

    Represents the seventh and all following elements: 7 [=0+7], 8 [=1+7], 9 [=2+7], etc.

  • :nth-child(3n+4)

    Represents elements 4 [=(3×0)+4], 7 [=(3×1)+4], 10 [=(3×2)+4], 13 [=(3×3)+4], etc.

  • :nth-child(-n+3)

    Represents the first three elements. [=-0+3, -1+3, -2+3]

  • p:nth-child(n)

    Represents every <p> element in a group of siblings. This selects the same elements as a simple p selector (although with a higher specificity).

  • p:nth-child(1) or p:nth-child(0n+1)

    Represents every <p> that is the first element in a group of siblings. This is the same as the :first-child selector (and has the same specificity).

  • p:nth-child(n+8):nth-child(-n+15)

    Represents the eighth through the fifteenth <p> elements of a group of siblings.

1 Like

:dart: Nailed

The more expressive power you give wikitext, the easier it is to reason about your code.

Something I read upthread, made me think this: wikitext can produce CSS but not the other way around. I think that’s worth remembering – because some things are better left said :stuck_out_tongue_winking_eye:

:coconut: Your proposal sounds pretty cool to me.

I love it! :stuck_out_tongue_winking_eye:

I think you have managed this above well. Of course there are many ways to do such meta tasks in TiddlyWiki and being able to reduce them to easier to use code snipits or practices is helpful.

  • Your examples are quite elegant, thanks for sharing.

So often the requirements can change a little and change the “best fit” solution as a result. For example in your case you want CSS to highlight alternating rows,

However as I said earlier;

I wrote such a solution by exploring writing a custom widget, the first I have written, and not just being a “script kiddy”. This first solution I will share focuses on the Odd even list only and involves no CSS but you could wrap either Odd or evens in CSS if you wanted. Here I just underline odd-items.

  • This works on tiddlywiki.com
  • Its not a competition just an illustration of the 5.3.x possibilities.

The widget definition in a tiddler with a global tag

\widget $list.odd.even()
   \function odd-even() [<item>remainder[2]]
   \function odd-even-proc() [<odd-even>match[1]then[odd-items]else[even-items]]
<$parameters filter="[all[current]]" $params=all-params>
<$list filter=<<filter>> counter=item>
           <$slot $name=<<odd-even-proc>>/>
</$list>
</$parameters>
\end $list.odd.even

Now use that widget as often as you want;

<$list.odd.even filter="[tag[TableOfContents]]">
<$fill $name=odd-items>
<<item>>  __<<currentTiddler>>__<br>
</$fill>
<$fill $name=even-items>
<<item>> <<currentTiddler>><br>
</$fill>
</$odd.even.list>
  • Provide the desired filter parameter
  • Modify if desired the content of the odd-items and even-items $fill widgets inside the widget call.
  • The fill widget makes it look verbose, but its actualy very simple to use.

The result is;

From the above I went down a rabbit hole, or was it a gold mine?, I am not sure but I did “waste” the good part of a day.

I have since taken the above design concept and written a new widget called
$list.report which includes the above functionality but goes a lot further in addressing a range common report list needs.

Like the above solution it makes use of $fill widgets, if they exist they are “transcluded” in the appropriate place within the widget definition and just work. I did not include a method to handle more than per items, odd and even, such as every 3, but you could place the logic to do so in a fill such as every-item.

  • The simples syntax is <$list.report filter="your filter"/>
  • Above is the odd/even treatment which still works with the new widget.
  • There are default that can be defeated with an empty fill

I will just share the documentation of this new widget now, but I am happy to share my development work for anyone interested;

Fill widgets for $list.report widget

  • ‘‘header’’ (default set) appears before all list items only if there is more than one item
    • The default or value provided in the emptyMessage parameter will be use if the filter has no result, Nothing else will show
  • ‘‘before-items’’ appears before any listed items (on same line)
  • ‘‘every-item’’ (default set) appears for every item
    • ‘‘odd-items’’ appears only for odd items in the list
    • ‘‘even-items’’ appears only for even items in the list
  • ‘‘after-items’’ appears after any listed items (on same line)
  • ‘‘footer’’ (default set) appears after all list items only if there is more than one item
  • ‘‘options’’ (default set) provides usage information, include <$fill $name=options/> to replace or include your own content.

Variables for use in $list.report widget

  • ‘‘currentTiddler’’ the name of each list item
  • ‘‘filter’’ a filter resulting in a list of tiddlers (also required parameter)
  • ‘‘emptyMessage’’ an empty message to show if not tiddler found (optional parameter)
  • ‘‘item’’
  • ‘‘items’’ total count of items as a result of the filter, also last item.
  • Default elements, can be reused
    • ‘‘default-header’’
    • ‘‘default-every-item’’
    • ‘‘default-footer’’
    • ‘‘default-options’’

The reason I have not released it yet includes;

  • Needs thorough testing
  • Demonstrate the power already inherint in this solution
  • I am working on aditional features
    • The ability to use ol and ul - li formating or columnification
    • Go beyond just item and items count totals, to allow a calculation / accumulation against all items.
1 Like

Not only for $list widget. As a filter operator, nth-child, would be wonderful.

If you did’t find it. In flex you could use the flex-direction property.

It feels more like an alternating mutual inspiration!

That’s beautiful! The only widgets I have built have been JS ones. This is the first non-demo one I’ve looked at with the new $slot mechanism. And now I actually understand how they work! Thank you.

This sounds like a fantastic idea. I can think of a number of occasions where this might have come in handy. I look forward to seeing it in action!

It sounds like it might be a wonderful idea, but I can’t quite imagine how it would work. Could you share a sample usage?

Yes, although I haven’t tested yet, I will probably rewrite that bit with row-reverse. I’ve used row and column but either never knew or had forgotten about their reversed twins. Thank you very much!

:thinking: No. I don’t see any general use, maybe it is a specific use for someone wants to play with statistics and weird views: how many cat there are in the numbers 4n of each streets and compare the numbers.

Wow, this is terrific. Please convert this post to a separate tip and trick thread.