Is there a way to use the journal-date field to organize journal entries with nested subsumes?

If first you drop it on tiddlywiki.com you can see how it works. Then you would need to modify the procedures within for each level and to suit your needs.

It seems the order year/month break is not your main requirement but that it is collapsible.

Subsume may be helpfull but its seems it is just one of a number of ways to open content.

I will reflect on this and see if I can give an answer. The wikis not online is it?

1 Like

Thank you for reminding me to test it on Tiddlywiki.com.

I went and dropped the json file on tiddlywiki.com and the code was easier to see.

I made a new tiddler with your example filter and experimented with removing lines from the end.

You are correct, I’m really hoping it can be collapsible. A tiddler containing years of journal entries would be unwieldy if I couldn’t open it in sections.

I also tried dropping the subsume plugin on tiddlywiki.com and adding parts of it to your code like:

<$list filter="[range[0],<top.index>]" variable=position counter=item>**<$macrocall $name=subsume tid=<<currentTiddler>>/>**
      <$list filter="[current.year[]!match<last.year>]" variable=year><<new-year>></$list>
      <$list filter="[current.month[]!match<last.month>]" variable=month><<new-month>></$list>
      <$list filter="[current.doy[]!match<last.doy>]" variable=doy><<new-doy>></$list>
      <<listItem>>
</$list>

But that didn’t work : (

To answer your last question: Alas, the wiki, being a private journal, is not online.

@Sapphireslinger my solution above allowed headers for each section without using nested lists. To make ìt all collapsible it may be easier to use nested lists in will share a simple example here soon.

Thank you. Looking forward to it!

I learned a tiny bit today. I figured out how to use regexp on the journal-date field to make a journal month tiddler without having to use a month tag:


<$list filter="[tag[Journal]has[journal-date]regexp:journal-date[^202204]sort[journal-date]]">
<$macrocall $name=subsume tid=<<currentTiddler>>/>
</$list>

But it doesn’t help the main goal which is to not have to manually make month tiddlers. I imagine it would be better to sliderize the dates list that your group-dates.json produces.

Meanwhile every so often I open up your group-dates json and stare at it. Someday it will no longer be greek to me. ^o^

Hi, I have only now got to review the suitability of my previous procedure Group-dates procedure.json to deliver your requirement, and I note that it is may not be suitable for your colapsable details view, because that most likely needs a nested structure, where my procedure avoids nesting in favor of detecting the change in year/month day.

  • Some CSS Wizz may be able to help.

I am keen on building a general solution for nested reports, but this is chalenging to design if it allows handling any number of nestings, that the user may specify. Although year/month/day is a common requirement.

  • I am sure you dont need to make month tiddlers, but hey if you can make it work, go for it.
  • In a way the method I used will “be somewhat difficult to understand by many” because it takes a whole new approach, so don’t be hard on yourself. It aims to be useable by everyone, not nessasarily understood by everyone (although some additional documentation would help).

The next step

I will start to investigate a solution to your problem and such problems in general. I expect it may still use a similar mechanisium, or a different structure all together. However here I am trying to write a general solution, innovate where possible and leverage some new tiddlywiki features to achive this, so my answer may not come too soon.

Here is a code pattern you may want to investitage in the mean time;

<$list filter="each year" variable=year>
Year header
   <$list filter="each month in year" variable=moy>
   Month header
      <$list filter="each day in month  of year" variable=dom>
         Day header
         <$list filter="each item" variable=item>
             Item header
                item template
             Item footer
         </$list>
         Day footer
      </$list>
   Month footer
   </$list>
Year Footer
</$list>

This could also be turned inside out item > dom > moy > year

  • The header an footer of each level could use the details widget (search for this and other options) to make everything inside it collaps.

The date functions inside my last procedure may prove useful for us both, and in future versions.

[Post script] It seems evident that breaking dates into years, months and even day of month is a very common need so extracting these to groups for nested lists would make sense as a subset of a more general nested list solution. The difference between each date group is as little as YYYY 0MM and 0DD.

  • Although there may be cases such as quarters, hours and minutes.

Thank you so much for the code pattern!

I added the detail widgets. That appeared to work nicely.

Then I searched for “extract year” in the forum and found List by year/month? with your code for extracting years and months from a field:

{{{ [{!!created}split[]first[4]join[]] }}}
{{{ [{!!created}split[]nth[5]] [{!!created}split[]nth[6]] +[join[]] }}}
{{{ [{!!created}split[]nth[7]] [{!!created}split[]nth[8]] +[join[]] }}}

So I tried adding <$list filter=“tag[Journal]has[journal-date][{!!journal-date}split[]first[4]join[]]” variable=year> but nothing happened.

<$list filter="tag[Journal]has[journal-date][{!!journal-date}split[]first[4]join[]]" variable=year>
<$details summary="Year header">
   <$list filter="each month in year" variable=moy>
<$details summary="Month header">
      <$list filter="each day in month  of year" variable=dom>
         <$details summary="Day header">
         <$list filter="each item" variable=item>
             <$details summary="Item header">
                item template
             </$details>
         </$list>
         </$details>
      </$list>
   </$details>
   </$list>
</$details>
</$list>

Your filter syntax is a bit borked! Try this:
<$list filter="[tag[Journal]get[journal-date]split[]first[4]join[]]" ...
Notes:

  • The filter was missing the initial open square bracket
  • The reference to {!!journal-date} will always refer to that field within the tiddler that contains the wikitext, rather than the tiddlers that match the preceding tag[Journal] filter operator.
  • Instead, use get[journal-date] to fetch the field value from the matched tiddlers. Note that has[journal-date] isn’t needed, since get[journal-date] only gives results for tiddlers that have a non-blank journal-date field… thus, has[...fieldname...] is automatically implied when get[...fieldname...] is used.

let me know how it goes…

enjoy,
-e

1 Like

That was a while ago, I would perhaps do this now in 5.3.x

\function get.year() [format:date[YYYY]]
\function get.month() [format: date[0MM]]
\function get.dom() [format: date[0DD]]

demo
* {{{ [{!!created}get.year[YYYY]] }}}
* {{{ [{!!created}get.month[0MM]] }}}
* {{{ [{!!created}get.dom[0DD]] }}}
  • Here you get the tiddlywiki date serial from where ever it is, in this case the created field {!!created} then use one of the custom functions/operators. Note the format can be anything here

@EricShulman thank you for elucidating the “get”.

However, it still did not work.

I did this:

<$list filter="[tag[Journal]get[journal-date]split[]first[4]join[]]" variable=year>
<$details summary="Year header">
   <$list filter="tag[Journal]get[journal-date]split[]nth[5]] tag[Journal]get[journal-date]split[]nth[6]] +[join[]]" variable=moy>
<$details summary="Month header">
      <$list filter="tag[Journal]get[journal-date]split[]nth[7]] tag[Journal]get[journal-date]split[]nth[8]] +[join[]]" variable=dom>
         <$details summary="Day header">
         <$list filter="each item" variable=item>
             <$details summary="Item header">
                item template
             </$details>
         </$list>
         </$details>
      </$list>
   </$details>
   </$list>
</$details>
</$list>

And got this:
experiment 02

Notes:

  • after changing the code: only one year header and one month month header and one day header and two item headers to choose from. (I should have multiple years and months and days of entries.)
  • before changing the code: the results were still erroneous, only showing two year headers to choose from, 4 month headers in each year to choose from, 6 day headers in each year to choose from, and 2 item headers (see below)

Before changing the code:

@TW_Tones, thank you for the updated code to try:

I tried this:

\function get.year() [format:date[YYYY]]
\function get.month() [format: date[0MM]]
\function get.dom() [format: date[0DD]]

<$list filter="[tag[Journal]get[journal-date]get.year[YYYY]]" variable=year>
<$details summary="Year header">
   <$list filter="tag[Journal]get[journal-date]get.month[0MM]]" variable=moy>
<$details summary="Month header">
      <$list filter="tag[Journal]get[journal-date]get.dom[0DD]]" variable=dom>
         <$details summary="Day header">
         <$list filter="each item" variable=item>
             <$details summary="Item header">
                item template
             </$details>
         </$list>
         </$details>
      </$list>
   </$details>
   </$list>
</$details>
</$list>

And got this:

  • I got over a hundred year headers, but I know I don’t have journal entries spanning a hundred years.
  • There are only two month headers appearing in each year, and only two day headers appearing in each month and two item headers in each day.

@EricShulman I found some old code that you helped me with 3 years ago: https://groups.google.com/g/tiddlywiki/c/H-teh7Cv0kg/m/VmhQqCTdBgAJ

I tried to repurpose it for here but that last list filter especially has me stumped. I hardly know how to formulate it. Any illumination you can give is appreciated.

Note: I no longer tag my journal entries with a year and month but they do have the journal-date field with this format YYYY0MM0DD0hh0mm0ssXXX

Note: My tiddlywiki is still 5.1.22 I did try out upgrading it recently for this project but the upgrade slows my whole wiki way down even after working on it for awhile so I went back to the older version for the present.

<$list filter="[range[2021,2023]]" variable="year">
   <$list filter="[tag[Journal]get[journal-date]split[]first[4]join[]limit[1]]">
      <<year>><br>
      <$list filter="[range[1,12]addprefix[$:/language/Date/Long/Month/]get[text]]" variable="month">
         <$list filter="[tag[Journal]get[journal-date]split[]nth[5]] [tag[Journal]get[journal-date]split[]nth[6]] +[join[]limit[1]]">
            &emsp;<<month>><br>
            <$list filter="[tag[Journal]search:journal-date[first[4]=<year>]sort[journal-date]] [tag[Journal]get[journal-date]split[]nth[5]] [tag[Journal]get[journal-date]split[]nth[6]] +[join[]=<month>">
               &emsp;&emsp;<$link /> <br>
            </$list>
         </$list>
      </$list>
   </$list>
</$list>

Just an update on bits of code I am trying that haven’t worked. Thanks for letting me put it here:

It occured to me that if <<year>> and <<month>> were what I needed the first six digits of the journal-date field to match then I could try this:

<$list filter="[tag[Journal]regexp:field:journal-date[^<<year>><<month>>]sort[journal-date]]">

But I’m sure the format is all off and it did not work.

Brave Leo AI suggested this:

<$list filter="[tag[Journal]]">
  <<year>>: <<month>>
  <<if $year == $currentTiddler.journal-date.substring(0, 4) && $month == $currentTiddler.journal-date.substring(5, 6)]>>
    <<$currentTiddler>>
  <<else>>
    <</if>>
</$list>

Note: <<year>>: <<month>> is probably nothing I want.

Note: I changed the 0,6 that was suggested to 0,4 and the 6,8 to 5,6.

Note: <<if $year == $currentTiddler.journal-date.substring(0, 4) && $month == $currentTiddler.journal-date.substring(5, 6)]>> seems like it’s so close to what I want. I really don’t want to bother with date per se, but just treat it as “Are the first six digits in the journal-date field matching the output of the year and month variables?” if that makes sense.

Note: I’m trying to solve this part of the code before I add any more code like reveal widgets.

Unfortunately, most LLMs don’t seem to know much about TW syntax, and they won’t tell you this, either. None of this is meaningful in TW:

<<if $year == $currentTiddler.journal-date.substring(0, 4) && $month == $currentTiddler.journal-date.substring(5, 6)]>>
    <<$currentTiddler>>
  <<else>>
    <</if>>

This is a good instinct! Here’s one way to do it:

<$let match=`$(year)$$(month)$`>
<$list filter="[tag[Journal]search:journal-date:anchored<match>]">

</$list>
</$let>

Notes:

  • I know the documentation can be a bit confusing on this point, but filter operators can only take an operand in one set of [ ] { } or < >, with no internal nesting.
    • Within a filter, we use…
      • [text] to refer to a literal value text (as you did with tag[Journal])
      • <text> to refer to the value of the “text” variable, defined outside the filter
      • { } to refer to a value being transcluded from a field (so {!!journal-date} will take the full content of the <<currentTiddler>>'s journal-date field, and {journal-date} will take the text field of the tiddler called “journal-date”, if it exists.)
  • This means we need to build the <<year>><<month>> combination before we can use it in a search.
    • Here, I’m using the $let widget to do it, because it lets me use substituted attribute values. Within the backticks, we have to use $(year)$ instead of <<year>>, but it’s easier to combine variables (and/or other text).
    • An “old-fashioned” way to do this might use <$let match={{{ [<year>] [<month>] +[join[]] }}}> or <$let match={{{ [<year>addsuffix<month>] }}}> instead. Here, we’re using filtered transclusion to assign the first result of a filter to the variable “match”. It’s obviously a bit less concise, since we have to use filter syntax to do it.
  • Once we’ve defined the target string and assigned it to a variable, we can use it in the filter.
    • regexp doesn’t really help us here, since it expects a regular expression, not a TW variable.
    • Instead, I used the search operator with the anchored flag, so it will look only at the start of the journal-date field.

There are other ways to do this (you could set the value of <<match>> with \define or \function, for instance) but I think this is probably one of the simplest. Let me know how it goes!

1 Like

If you have the date from which you would obtain year and months use this approach;

[{!!journal-date}format:date[YYYY0MM]] and use this for your tests.

As someone who is not familiar with RegEx, I figured I would give this a shot:

<$list filter="[tag[Journal]get[journal-date]format:date[YYYY]each:value[]sort[title]]" variable="YEAR">
<details>
<summary><strong>Journal <<YEAR>></strong></summary>

<$list filter="[tag[Journal]get[journal-date]prefix<YEAR>format:date[YYYY MMM]each:value[]sort[title]]" variable="YEARMONTH">

<details>
<summary><<YEARMONTH>></summary>

<ul>
<$list filter="[tag[Journal]] :filter[get[journal-date]format:date[YYYY MMM]match<YEARMONTH>]" variable="ENTRY">
<li><$link to=<<ENTRY>> />&emsp;(<em><$view tiddler=<<ENTRY>> field="journal-date" format="date" template="YYYY-0MM-0DD"  /></em>)
<br><$transclude tiddler=<<ENTRY>> /></li>
</$list>
</ul>
</details>
</$list>

I don’t know if this will hold up when using a lot of entries, but it might give you some ideas.

1 Like

@Brian_Radspinner I think the code pattern within your example and variations of it is a useful approach to this and similar problems. In this one you are nesting the lists, but we can also use the format date (to different periods like YYYY) then the each:value[] to get a list of those values, we can save this in a variable, using $set filter= in this case the years in our data set.

  • Then we can use this as the outer group
  • Then we could go on to determin another set of the form YYYY0MM
    • No need in this case because this is the key to inner group

If this set of years, is in a variable, before we use it we could give the user the opportunity to select from that set and use the result to itterate the data.

  • I am interested in exploring this pattern because it is a way to allow selection of a range of date based on the date itself.
  • Note each:value[] seems equivalent to unique[]

I will edit this reply and give an example, the following example uses journal entries with a journal-date

\function month-heading() Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec +[nth<month>]
<$set name=journal-years filter="[get[journal-date]format:date[YYYY]each:value[]!sort[]]">

''Years to include: ''<$list filter=<<journal-years>> variable=year>
<$checkbox listField="temp-years" checked=<<year>> unchecked=""> <<year>>,</$checkbox>
</$list>
<$list filter="[enlist{!!temp-years}]" variable=year>
<details><summary>Year <$text text=<<year>>/></summary>

<$list filter="[range[12],[1]pad[2]]" variable=month>
<$let date-prefix={{{ [<year>addsuffix<month>] }}}>
<details><summary><<month-heading>> ^^<$text text=<<year>>/>^^</summary>
<$list filter="[has[journal-date]!nsort[journal-date]] :filter[get[journal-date]prefix<date-prefix>]">

</$list>
</details>
</$let>
</$list>


</details>
</$list>

</$set>

And looks like this;

Snag_34992fe

  • After opening Year 2023 and Month Dec

Notes;

  • Notice how month-heading is an array that uses <<month>> to find an entry in it.
  • Selecting the years shows how we can use and save such parameters for perfomance
  • There are 12 month in any years so I generate them rather than look them up, (we could have empty months, so you could add a count of journals to the month summary).
    Snag_351a9da
2 Likes

Wow, the explanations are all so fascinating! So many things to try, and links for further study. Thank you everybody!

. . . some time later . . .

@etardiff

I loved the links and explanations! But I could not get any of your link suggestions to work, neither in 5.1.22 nor the upgraded version. I think the problem is not your code but the code I was trying to plug yours into.

@Brian_Radspinner

The Holy Grail! Your code was the closest to what I wanted and it was EXACTLY what I wanted after I tweaked this part of your code:

<ul>
<$list filter="[tag[Journal]] :filter[get[journal-date]format:date[YYYY MMM]match<YEARMONTH>]" variable="ENTRY">
<li><$link to=<<ENTRY>> />&emsp;(<em><$view tiddler=<<ENTRY>> field="journal-date" format="date" template="YYYY-0MM-0DD"  /></em>)
<br><$transclude tiddler=<<ENTRY>> /></li>
</$list>
</ul>

. . . to this:

<$list filter="[tag[Journal]] :filter[get[journal-date]format:date[YYYY MMM]match<YEARMONTH>]" variable="ENTRY">
<$macrocall $name=subsume tid=<<ENTRY>>/>
</$list>
  • I got rid of the <ul> etc because I didn’t need the extra indent.

  • At present I didn’t need the date appended to the title because the date is currently the beginning of my title. (It’s a holdover from old habits and ways of sorting and considering a bit of redundancy as an extra margin of safety. But I may use it in the future.)

  • I saw what you did with variable=ENTRY and tried plugging ENTRY into David Gifford’s subsume macrocall a la <$macrocall $name=subsume tid=<<ENTRY>>/> and voila . . the holy grail! Even though it’s not subsumes all the way up, it’s exactly what I wanted!

HOWEVER, your code (changed or unchanged) will not work in 5.1.22, only in the 5.3.1 version. How do I get it to work in the old version?

Would it have something to do with format:date not being recognized yet in the old version?

@TW_Tones

  • I was able to get the subsume macrocall to work in your code as well.

  • Likewise your code only works in 5.3.1 not in 5.1.22 but I think that is natural because you are concentrating on using the latest.

Once again, thank you everybody so very much!

The :filter prefix came in with 5.1.23, so it just missed your cut-off requirement. You can try this alternative version with the Subsume macro:

<$list filter="[tag[Journal]get[journal-date]format:date[YYYY]each:value[]sort[title]]" variable="YEAR">
<details>
<summary><strong>Journal <<YEAR>></strong></summary>

<$list filter="[tag[Journal]get[journal-date]prefix<YEAR>format:date[YYYY MMM]each:value[]sort[title]]" variable="YEARMONTH">

<details>
<summary><<YEARMONTH>></summary>
<$list filter="[tag[Journal]has[journal-date]]" variable="EVERY-ENTRY">
<$list filter="[<EVERY-ENTRY>get[journal-date]format:date[YYYY MMM]match<YEARMONTH>]" variable="EACH-ENTRY">

<$macrocall $name=subsume tid=<<EVERY-ENTRY>>/>
</$list>
</$list>
</details>
</$list>

And a more generalized version without subsume:

<$list filter="[tag[Journal]get[journal-date]format:date[YYYY]each:value[]sort[title]]" variable="YEAR">
<details>
<summary><strong>Journal <<YEAR>></strong></summary>

<$list filter="[tag[Journal]get[journal-date]prefix<YEAR>format:date[YYYY MMM]each:value[]sort[title]]" variable="YEARMONTH">

<details style="margin-left: 1em;">
<summary><<YEARMONTH>></summary>
<ul>
<$list filter="[tag[Journal]has[journal-date]]" variable="EVERY-ENTRY">
<$list filter="[<EVERY-ENTRY>get[journal-date]format:date[YYYY MMM]match<YEARMONTH>]" variable="EACH-ENTRY">
<li>
<$link to=<<EVERY-ENTRY>> />
<br><$transclude tiddler=<<EVERY-ENTRY>> />
</li>
</$list>
</$list>
</ul>
</details>
</$list>

@Brian_Radspinner
Both codes return a blank tiddler in 5.1.22

Just popping in to say you were right about format:date being an issue; the format operator itself was only introduced in 5.1.23.

Sorry my code didn’t end up working for you! I didn’t read the thread as closely as I should have and wasn’t thinking about older versions of the core.