Modifying wikitext for headers to be collapsible?

So, to preface this, one of the features I’m a pretty big fan of in other applications is the ability to collapse headers, and while there are other methods available to do this, I find myself using the built in wikitext formatting to define headers even when I’m not writing a tiddler, just because of how efficient it is to do so.

So, that’s why using divs, or macros isn’t really something I want to do, as I don’t think I will be satisified with that in the long run. Its also just one feature I’m looking for, so having multi-feature plugins isn’t really preferred because it feels like I’m installing things I don’t have any use for along side it…

So my question is, in more experienced users opinions, how difficult would it be to modify or clone the $:/core/modules/widgets/element.js tiddler in such a way to change the behavior of the header wikitext formatting to wrap around text if it under it?

My plan is instead of just the header being wrapping in <h1-6> elements, instead the header would be wrapped in a details disclosure summary element, and generate the closing details tag after whatever text is underneath the header, as long as it isn’t more than one line break away.

for example, original formatting would be:

!!! Hello There
"""
How are you?
"""

resulting in:

<h3>Hello There</h3>
<p>
How are you?
</p>

And revised formatting result would be:

<details>
 <summary class="h3">Hello There</summary>
<p>
How are you?
</p>
</details>

(I can easily make a .h3 css class to match the defaults of what an h3 element renders as both by mozilla standards and by tiddlywiki’s vanilla stylesheet, so that is implied with the summary class.)

I was looking at how other javascript tiddlers handle similar functionality and thought of the bullet wkitext, but i guess even that doesn’t really apply the same, since what I am aiming for could technically count as turning an inline element into a block element, no? Edit: please ignore this part, I was thinking something waay different, what I meant to put is “a single element into an element with children elements inside it.”

On this note about how difficult it might be, if it is something that is out of my own skill range, I would be happy to open a bounty of sorts for the development of it, but TBH I’m not entirely sure how bounties are meant to work with the community as of right now, we’ve had so few that it’s a bit vague haha

Anyways, to get back on point, any insight would be appreciated!

Gotta say, right away, you’re heading (excuse the pun) down a semantically unsound path: headers are not disclosures are not headings, IMV.

And modifying a core .js file? I wouldn’t go there. What you’re aiming to do might be simple enough, but I wouldn’t do it.

Perhaps @jeremyruston et al have a better approach.

@pmario did have a custom parser plugin under development. Maybe he has some ideas?

1 Like

Sigh yeah, I 100% agree with you, but i don’t know of a way of getting that functionality with a header element, and using a reveal widget would be the same, well even a bit more technical, than the details disclosure element, thus why I picked it, but yeah, as far as accessibility, it breaks a lot of rules.

I don’t like modifying core tiddlers at all, but I’m unsure if you can override javascript tiddlers without replacing their code. I’ve had mixed results with getting them to in the past.

Custom parser would be awesome actually. I hadn’t considered that, also maybe if i just edited the viewTemplate to render headers differently then changing the wikitext wouldn’t need to be an issue :thinking: not sure if thats possible in that way though…

Consider (I mean REALLY think about it) the tabs macro. What does it actually do?

A series of button elements switch between a series of div elements.

Said another way, make-selected a specific button, make visible a specific div.

If you styled the tabs macro bits and pieces significantly differently, (the buttons in particular) you’d never know they were “tabs”. I’ve done it. The buttons were nowhere near the “tab panels” (divs) they made visible.

I’m not saying use the tabs macro. I’m saying, think differently about the elements/widgets available to you.

I’ll have to take a bit to mull that over, but when it comes to this specific topic, I’m less concerned with how it is achieved, and moreso the end result not changing how headers are formatted, or having to add too much extra to my TW if it can be avoided.

I’m looking for a way to type !! Header and have the intended result, without the need to do something like

@@h2 Header

text here.
@@
(or)
<$header lvl:"2" title:"Hello There" """Text Here""">

Or similar alternatives.

Thats why the mention of Pmarios custom parser has my curiousity :grin:

1 Like

Okay, how about this (in brief, untested, obviously)…

Now that we have $eventcatcher, ~everything is clickable. For the tiddler containing the heading(s) you can glean from $eventcatcher which heading was clicked and set it as selected in a field on that tiddler:

// pseudo code
Clear out any previously selected header
Set the clicked header as the selected header

Now use CSS to apply styles to <div>s following <hN>s. You can target an immediate sibling of <h1> with:

h1 + div {
  display:none;
}
h1.selected + div {
  display:block;
}

Crude, but effective. Animating the height would be nice instead of bluntly displaying it.

Accessibility score? TERRIBLE.

Understand, this is a brain dump. I’ve likely forgotten something key…

1 Like

Well, the idea right now is brainstorming how, and if its possible or if its too difficult etc. so I think this is the right path for progress.

eventcatchers sort of remind me of :hover and :selected.

ATM i have to head to sleep for work, so sorry if any future replies are made, I’ll be returning to this when I wake up. Here’s hoping I can dream up some way of doing this haha

ditto :wink:     

1 Like

Hi @Justin_H @CodaCoder the desire for clickable headings is not unreasonable, and there might be a way to accommodate it.

It’s a bit roundabout, but one approach is that we could have an alternate heading parser that arranges the headings into an <ol> list structure, with the text between headings going into the <li> element. To make things clickable one would then use custom widgets to override the <ol> and <li> elements (although at the moment it is not possible to override HTML elements with a custom widget, but that is something I would like to improve).

So, for example:

! Heading 1

Some text.

!! Heading 1.1

More text

! Heading 2

Some more text

Would be parsed as:

<ol>
  <li>
    <h1>Heading 1</h1>
    <div>
      Some text.
    </div>
    <li>
      <h2>Heading 1.1</h2>
      <div>
        More text
      </div>
    </li>
  </li>
  <li>
    <h1>Heading 2</h1>
    <div>
      Some more text
    </div>
  </li>
</ol>

We would need to devise a way to engage the alternate parser behaviour.

A simple option would be to package it as a separate parser rule that is switched off by default, and requires enabling with a pragma.

It would be preferable to find a way to signal the alternate approach with wikitext markup. For example, we could mark the opening heading with a period: .!. The natural way for the parse rule to behave would be to switch to the alternate behaviour when the first dot header is encountered, and then use the alternate behaviour for all the remaining headings, regardless of whether they are marked with a dot.

1 Like

Me like. Keeps with hN and !.

I don’t suppose its possible to have this be optional is it? If not and the period would be required to trigger the parser then no worries.

Otherwise, this sounds like it would be awesome.

Whatever. Here’s the bare bones of a solution using current tech:

ExpandCollapse Headers.json (740 Bytes)

1 Like

This is cool, the only real contribution I can make atm is offering the idea of using the content feature of css to add mock toggle buttons

<style>
h1 { cursor:pointer; }
h1:before { content:"+"; }
h1 + div { display: none; }
h1[data-id={{!!selected-header}}] + div {
  display: block;
}
h1[data-id={{!!selected-header}}]:before {
content:"-";
}
</style>

I’m wondering if the content can be replaced with transcluded icon tiddlers, but probably not.

Also, if we use the header text as the id, slugifying it, then I think it can be trimmed down

There’s always something better :wink:

or, perhaps…

h1:not(.keep-open) + div { display: none; }

or…

h1:not([keep-open]) + div { display: none; } /* untested */

I suppose so, though probably not from me :sweat_smile:
As an addendum to that though, trimmed like, being able to use it for more than just the H1 elements without having to just duplicate the parameter.

1 Like

That’s just about the CSS selectors:

h1,h2,h3,my-element ... {  ...  }

Unless I’m misunderstanding you…

With sliding animations and the boolean attribute keep-open on one header:

ExpandCollapse Headers 0.2.json (2.2 KB)

@Justin_H you should add your CSS for content properties and call it 0.3.

Sure, here (ExpandCollapse Headers 0.3.json (2.3 KB))
is the CSS for adding content before the header, though I haven’t figured out how to use the header wikitext in the same way as the header html elements.

Is there syntax for adding element id’s to the ! header? Also, in the event a selected-field is not present, ie it is transcluded into another tiddler, what sort of behavior should be expected? will it still pull its open state from that targetTiddler or since the shorthand used is pulling with currentTiddler, will it use the transcluding tiddler to generate a new field? :thinking: I’ma play with this a bit.

I’m thinking using

h1:not([keep-open]):after {
content:"...";
color: <<colour muted-foreground>>;
}

might look more aestetically appealing since we don’t have to conform to the open and close icons of a details disclosure. I experiemented with hover to show and hide the content text but, ehh… i think muted-foreground is the way.