How to make $slot and $fill palatable

I am really trying to figure out what the new $slot and $fill feature is good for, and I’m struggling. Every time I try to even create a hypothetical scenario for them, I get something way more clunky than if I’d just used macros. The whole $slot and $fill stuff is so verbose. I guess that’s not a problem for the \widget definition, but it seems cumbersome to make end users use <$fill $name=“blah”>Content</$fill> every time they want to fill a slot. On top of that, if you use any slots, you must use ONLY slots, because the ts-raw will become polluted with the others.

I thought make it might be useful if you could encapsulate the $fill somehow like this:

\widget $my.widget()
''Title:'' <$slot $name=title>Untitled</$slot>
<$slot $name=ts-raw/>
\end

\widget $my.title() <$fill $name=title><$slot $name=ts-raw>Empty</$slot></$fill>

<!-- What I have below might theoretically be useful, except it doesn't work -->

<$my.widget>

<$my.title>My Title</$my.title>

Content
</$my.widget>

But this doesn’t work. And this also shows off how tw-raw gets polluted by the contents of the $my.title widget. (Or the fill widget. Either will pollute.)

Could somebody explain to me what this feature is supposed to be elegant for?

I wanted <$fill $slot=title>. You know, akin to $transclude now using $variable instead of $name ← just too generic-sounding. I mentioned it on Github early enough and @jeremyruston said he liked it but it never happened.

Up to now, I’ve only had a use for ts-raw – can’t predict what the future might ask me for :confused:

There is a discussion over at GH about the $slot widget and ts-raw.
See: [IDEA] Provide another generic slot widget · Issue #7836 · Jermolene/TiddlyWiki5 · GitHub

Note that transclusions are far more flexible in terms of using slots/fills as compared to custom widgets, see https://tiddlywiki.com/#TranscludeWidget:TranscludeWidget%20SlotWidget

I believe the intent with custom widgets was to provide a means to override JavaScript widgets as needed, rather than provide a means for packaging reusable functionality. For the latter, transclusions offer more flexibility. The downside is that invoking transclusions is rather more verbose than custom widgets. A shortcut syntax would be very useful.

@Flibbles I feel you pain, but I am getting there.

  • This is one reason and will typically be used along with the genesis widget.

However the ability to write custom widgets makes it easy to build solutions that make use of the content of the widget, so it is easier and cleaner to provide a block of wikitext to a custom widget than to macros or procedures.

I do however agree with @Flibbles that the fill widget is somewhat verbose and does not provide an easy way for users to provide additional “blocks/lines” of content to a custom widget.

Yes I was involved in this because there is a limitation that needs addressing.

However if you want to see the possible power of custom widgets consider my $list.report widget which you can use instead of the list widget directly, just provide the filter. It has default headers and footers, item numbers, total items and more. But if you provide the content of the header footer etc… inside a fill widget that will be used instead.

  • The content of a fill widget can easily contain a block of content not just a single line.
  • Custom widgets can combine the “power” of multiple widgets into one but has the advantage of having natural names $list.report instead of <$transclusion $variable=procedure
    • Note the <$macrocall $name=procedure/> still works with the new procedures and is only slightly limited.

A solution to the verbosity of the fill widgets?

As inside my list Report widget for a use to add a custom header/footer they need to enter the following;

<$list.report filter="[tag[TableOfContents]]">
   <$fill $name=header>

      !!Your report header
   </$fill>
   <$fill $name=footer>
      <small>Your report footer</small>
   </$fill>
</$list.report>

My thoughts are can we create a less verbose and more meaningful alias for the fill widget?

  • Perhaps also allowing the slot widget to set block or inline mode, avoiding the need for a blank line to force block mode.
  • Perhaps we can use the genesis widget to create an alias to the fill widget? However its getting rather self referential.

Speculation
What if the slot widgets could be given the name of an arbitrary html “section” and pull that in rather than use using the fill widget?

<$list.report filter="[tag[TableOfContents]]">
   <header>!!Your report header</header>
   <footer><small>Your report footer</small></footer>
</$list.report>
  • It may make resolution of the following more difficult.

Yeah. I suspect that if anyone starts using any fill slots other than ts-raw, they are making too complicated of a solution.

Yeah, it looks like you’ve found a use for /widget, and it also looks like you agree that it’s over verbose. Before v5.3.x, I would have done something like this:

<<list-report "[tag[TableOfContents]]"
header:"""

!!Your report header
"""
footer: """

<small> Your report footer</small>
""" >>

Funny thing is, even though I’m committing the cardinal sin of putting wikitext into attributes, this works just fine. I use patterns like this all the time (and it’s less verbose).

What I would love is if the pattern I described above would work. I think that would be a super clean solution. E.G.

\widget $list.header() <$fill $name=header><$slot $name=ts-raw>Empty</$slot></$fill>

If that could work, then this would be a neat feature. I guess the widget doesn’t unfold enough in the parse tree or something? Not sure why the outer $list.report couldn’t find that buried $fill.

I don’t think it (blocks in procedure calls) is a sin, I just find it fragile and also hard to explain. I also think it looks ugly.

  • I am not sure I follow your example.

My idea is that the <$fill $name=header>Content Here</$fill> could be wrapped in another custom widget, so then you could call <$list.header>Content Here</$list.header>.

I think that provides something nicer to end users. Plugin developers could develop a small suite of widgets designed to be nested within each other, and it’s a lot easier than instructing end users to use stuff like <$fill $name=...>... when they probably won’t even know what $fill is. (I think we can all agree it is not a widget for beginners.)

Agreed, perhaps we can use the Genesis widget to redefine the fill widget?

  • I/we will have to experiment.
1 Like

Here is my first attempt, not working any ideas?

\procedure section(name content:"default")
<$genesis $type="$fill" $$name=<<name>>><<content>></$genesis>
\end
\widget $test.widget()
<$slot $name="test"/>
\end $test.widget

<$test.widget>
<<section test "section content">>
<!-- <$fill $name=test>
Content
</$fill> -->
</$test.widget>
  • I suspect since the fill widget is only valid in side a widget, using the genesis widget to redefine it outside the widget, it will not work?
  • Wonder if we could dump the fill/slot widgets and somehow use html sections and arbitrary tags?

I think you’re hitting the same problem I did. You’re right that unless the fill widget is directly inside the widget it’s trying to fill, it won’t work, which is disappointing.

Using html sections and arbitrary tags I think would introduce the potential for conflicts without much more benefit. Imagine that your \widget uses a slot for the tag section. When people use your widget, they could use section as a fill, but they can no longer use section as it was originally intended under HTML5. The \widget could just as easily explicitly define another widget to be used alongside of it using the $ syntax, and that would be exactly as verbose as using html5 tags, but more maintainable I’d think.

Too bad none of these ideas work though.

Yes, the only way I can thing of to reduce the verbocity of fill widgets is to reduce it from <$fill $name="headder">...</$fill> to something like <$.header>...</$.header> but then it becomes “bespoke”, or if there were some special symbols like &header& … /&header& (just a guess) that automagicaly creates a fill widget the slot could access.

I have to say, it’s a shame this wasn’t brought up in the lengthy discussions during the lead-up to 5.3.0.

Perhaps this is a lesson for the future, Github isn’t enough.

Yeah, I would have brought up a lot of things in that discussion, but I wasn’t really involved in the community for a few months. I’d have had some things to say.

But even so, the thing we’re proposing here would just be an elaboration on what’s already done. It shouldn’t be too hard to implement now (I hope). It wouldn’t break any backward compatibility (I think), and it’s an intuitive application of the \widget (I believe).

My personal view is in github it was a large body of work undertaken by developers and the proposed changes where never documented maturely enough that super users could understand it enough, to then provide feedback, let alone do any user testing.

  • I did my best to contribute but then it was not easy as every attempt needed hours of prereading and trying to understand, let alone forecast how it will look as a user, was next to impossible.
  • There was a lot of motivations in the core team to make changes, all good and well, but every change can have an impact of the users naive or otherwise and it is hard sometimes as a developer in the know, to imagine how others read it, and would use it.

The slot and fill widgets are indeed clumsy within custom widgets because they force the caller to use a generic <$fill> widget which may not be a good match for the semantics of the custom widget.

The intention is to allow transclusions to reach into the parse tree nodes of the contents of the calling transclusion, and find and extract whatever widgets it wants. Thus a custom widget could define its own custom sub-widgets. This matches the way that JavaScript widgets are constructed: they have control over how their contained widgets are rendered.

We do already provide access to the parse tree nodes via the <$parameters> widget, but doing this will require quite a bit more infrastructure concerned with manipulating parse trees: JSON treewalking operators that can be used to search for custom widgets, and the ability to transclude a parse tree directly. And a suitable high level syntax.

Those are useful features in any case, and will enable us to address some other long-standing concerns.

2 Likes

I must admit, I’m having trouble understanding what you’re trying to say.

I mean, even with the <$parameters>, it looks like someone has to resort to using <$fill> widgets in order to fill slots. But it sounds like you’re saying (and correct me if I’m wrong), that end users are never expected to do this??? That all this intricate transclusion is designed for plugin developers to make… elaborate templates, or widgets?

It still seems like however it’s cut, whether for custom widgets or transcluded templates, it’s still this clunky syntax that requires users to have the documentation open.

And about that, is there an effort underway to improve the documentation? Because I’m trying to update Relink and Uglify, and so I’m having to make myself abreast of all these new features, like <$slot>, <$fill>, and <$parameters>, (and $depth), and I still have no idea why anyone would use these things.

I guess I should ask how anyone would use these things. I can see the benefits of having custom widgets (parameterized tiddlers, not so much).

But I have yet to think of a use case that wasn’t already covered by existing TiddlyWiki techniques.

In the 5.3.2 prerelease we have the introduction of

support for <$list-template> and <$list-empty> as immediate children of the $ListWidget widget to specify the list item template and/or the empty template.

  • Personally I am not sure of the value, including the <$list-join> because I personally have what I feel are better ways to do the same.

However It makes me wonder, if inside the custom widgets, the naming of the slot widget could itself look for a matching fill widget, but a custom one, by the name used in the slot widget.

<$slot name=reportbody/>

Would then “look for” <$reportbody>something</$reportbody> rather than the fill widget, instead a automatically named custom widget.

I am sure it depends on the way the code works but this would be an acceptable approach, to me.

However I think an additional feature could be made to support this, have a more powerful feature added. I will update this reply soon.

[edited]

Perhaps someone here has some ideas but could we perhaps define custom widgets that can replace a generic fill widget, perhaps using the genesis widget that can replace the use of generic fill widgets with specific named ones, not unlike the list-template/list-item/list-join templates?

So then we can call our custom widget, containing custom fill widgets?

<$my.widget  params
   <$name1>a</$name1> 
   <$name1>b</$name1> 
</$my.widget>

and within $my.widget

<$slot name=name1/>
<$slot name=name2/>
  • part of this motivation is while making our custom widget is in “design time” and we can cope with obtuse widgets like $slot, but calling $my.widget is in “author time”, when we use and apply our development work. And we do this authorship multiple times, so the value of ease of use and reading, is much more valuable in the calling widget.