How to space fill numbers?

Folks,

The following macro “list-items” runs on the prerelease ONLY and it lists items using the new counter variable. Try an alternate filter.

\define list-items(filter:"[tag[TableOfContents]]")
<$set name=items filter="$filter$ +[count[]]">
<$list filter="$filter$" counter=item>
   <<space-items>>. <$link/><br>
</$list>
</$set>
\end
\define space-items(max)
\whitespace trim
<$set name=max value="$max$" emptyValue=<<items>> >
<$set name=places filter="[<max>length[]]">
<$set name=magnitude filter="[[10]power<places>]">
<$text text={{{ [[$(item)$]divide<magnitude>fixed<places>removeprefix[0.]] }}}/>
</$set></$set></$set>
\end

<<list-items>>

The second macro space-items makes use of the variables <<item>> and <<items>> and provides leading zeros “000” so all the numbers align. This may useful in itself however I would like the leading zeros to be replaced with spaces and not disappear from the result, so the numbers all remain aligned.

I am posting to see if anyone can solve this problem with the “space-items” macro or has a better way to do it altogether.

Once solved I will move to How to with an ! not a ? in the title.

Here’s two methods…

The first method uses CSS display:inline-block;text-align:right with a fixed-width based on the maximum number of digits (“places”) and the width of a “0” (CSS units=“ch”):

\define list-items(filter:"[tag[TableOfContents]]",pad:" ")
<$vars places={{{ $filter$ +[count[]length[]] }}}>
<$vars style={{{ [[display:inline-block;text-align:right;width:]addsuffix<places>addsuffix[ch]] }}}>
<$list filter="$filter$">
   <$vars item={{{ $filter$ +[allbefore:include<currentTiddler>count[]] }}}>
   <span style=<<style>>><<item>></span>. <$link/><br>
   </$vars>
</$list>
\end

The second method uses a borderless table, with text-align:right for the cell containing the numbers and doesn’t need to calculate the maximum number of digits (“places”)

\define list-items2(filter:"[tag[TableOfContents]]")
<style> .borderless table, .borderless tr, .borderless td { border:0;padding:0;margin:0; } </style>
<span class="borderless">
<table>
<$list filter="$filter$">
   <$vars item={{{ $filter$ +[allbefore:include<currentTiddler>count[]] }}}>
   <tr><td style="text-align:right;"><<item>>.&nbsp;</td><td><$link/></td></tr>
   </$vars>
</$list>
</table>
\end

Note:
<$vars item={{{ $filter$ +[allbefore:include<currentTiddler>count[]] }}}> is equivalent to counter=item, but is compatible with TW5.1.23

enjoy,
-e

1 Like

Thanks Eric,

Beautiful choices. I was looking at allowing color And columns to be provided so perhaps it makes sense to go with the style attribute method and leverage the same method. Critical to this is your CSAS knowledge, thanks!

I thought of a table but forgot the borderless option, this approach has the advantage of allowing me to introduce other columns programaticaly.

By the way the counter is possibly much more efficient than
<$vars item={{{ $filter$ +[allbefore:include<currentTiddler>count[]] }}}> however as you say backwardly compatible.

It is the counter that inspired me because I am creating a list-report macro that provides a header and footer above and below the list. Kind of like the old ForEachTiddler from TWC.

In the second example is that a self closing span?

Hmmm, more thinking to do. Thanks again.

Post script: I keep forgetting the “filtered transclusion” can be used to set variables in the varwidget, and filters can effectively return the emptyValue condition with else. Love it.

In the second example is that a self closing span?

In macros, anything that isn’t explicitly closed by the end of the macro is automatically closed.

In the first macro, I don’t bother to close the <$vars ...> with matching </$vars>
and, as you noted, in the second macro, I used a <span ...> without a matching </span>

Note that this coding technique only works for the outer level. Thus, the <$vars> inside the <$list>...</$list> needs to be explicitly closed.

By the way the counter is possibly much more efficient …

Yeah, I expect so, because the filter is being re-evaluated for each item.

-e

1 Like

When filtered transclusion is used to assign a value to a widget parameter, only the first item resulting from the filter is used, so <$vars foo={{{ [...] }}}> only works if the filter produces a single value. If you need to “capture” a list of items in a variable, then <$set name="foo" filter="..."> is the way to go.

-e

1 Like

Can you use the pad[4][ ] operator for this? Note the second operand for specifying the pad character.

https://tiddlywiki.com/#pad%20Operator

By the way there is a special variety of space character in Unicode that is intended to be the same width as digit characters:

In wikitext:

<$vars
  figureSpace={{{ [charcode[8199]] }}}
  number=829
  >
    <$text text={{{ [<number>pad[8],<figureSpace>] }}}/>
</$vars>
2 Likes

Hi,
Please be aware of the “note” at: https://tiddlywiki.com/prerelease/#ListWidget

Note that using the counter attribute degrades the performance of the list widget because it prevents the optimisation of refreshes by moving list items around instead of rerendering them.

The performance hit can be significant! So it should only be used if there is no other way to solve a problem.

1 Like

In HTML we have unordered list and ordered list. If I understand well the issue, I think that ol works perfectly for you.

\define list-items(filter:"[tag[TableOfContents]]")
<ol>
<$list filter="$filter$" >
   <li><$link/></li>
</$list>
</ol>
\end

@jeremyruston thanks, I thought there was an operator but could not find it. This works in v5.2.0+ because that is needed for [charcode[8199]] however once generated I was able to copy one of those spaces and paste it into 5.1.23 it then worked in pad[ ]
<$set name=space value=" ">

It may be worth adding this to the doco`

@pmario It would be helpful to know how big an impact counter has a poor performance. If not used in a “always open tiddler” or an active sidebar tab .

I will update the lead thread later!