[Idea] Custom Text-Body Templates (worth a Core Pull Request)?

254 views
Skip to first unread message

Joshua Fontany

unread,
May 24, 2020, 3:34:06 PM5/24/20
to tiddly...@googlegroups.com
So I have decided to edit a core system tiddler (gasp) for my current 2 projects. One is a Martial Arts Wiki, with a glossary of over 500 Indonesian, Malay, Sundanese, Filipino, Javanese, Hawaiian, and Chinese terms with special martial-arts context-specific meanings, and a ton of Bookmarks (YouTube, etc). The other project is the every-growing UnNamed RPG Campaign Manager, and one of the biggest roadblocks there was "custom character/ship/etc sheets".

I think I have a solution for this one. Will it be PR worthy? Let's find out. The ability to hide/replace the default text field is a bit cumbersome atm. You can hide the text-body by setting the `hide-body` field to "yes". And we can add new "sections" with `$/tags/ViewTemplate`, but unless we dig around and copy the $reveal code from another template section that will not be consistent with the Collapse state.... Yeah. Complicated.

If I change the `$:/core/ui/ViewTemplate/body` tiddler slightly, we can move the "tiddler-body-default" wikitext to a macro in the same tiddler:
```
\define tiddler-body-default()
<$list filter="[all[current]!has[plugin-type]!field:hide-body[yes]]">


<$transclude>


<$transclude tiddler="$:/language/MissingTiddler/Hint"/>


</$transclude>


</
$list>
\end

```
And re-write the body of the tiddler like so:
```
<$reveal tag="div" class="tc-tiddler-body" type="nomatch" stateTitle=<<folded-state>> text="hide" retain="yes" animate="yes">


<$list variable="bodyTemplate" filter="[all[current]subfilter{$:/config/ViewTemplate/Body}]" emptyMessage=<
<tiddler-body-default>> >


<$transclude tiddler=<
<bodyTemplate>> >


<$tiddler tiddler=<
<bodyTemplate>> >


<$transclude tiddler="$:/language/MissingTiddler/Hint"/>


</$tiddler>


</$transclude>


</$list>


</$reveal>

```
Then we can use an array of filters to check for tags, type, or any other way you want to trigger a custom view template, and you can have more than one resulting bodyTemplate titles output and it's all nested in the correct $reveal widget, etc. Even better, you can use the `<<tiddler-body-default>> macro ANYWHERE in your own templates to get the default text-field to show up in that spot. Here is my current `$:/config/ViewTemplate/Body`:
```
[tag[$:/tags/Macro]then[$:/plugins/joshuafontany/core/ui/ViewTemplate/body/macro]]
[tag[Glossary]then[$:/plugins/joshuafontany/silatglossary/ui/ViewTemplate/body]]
[match[Test]then[$/plugins/joshuafontany/core/ui/ViewTemplate/body/TEST]]

```
Which as you can see, uses the `$:/plugins/joshuafontany/core/ui/ViewTemplate/body/macro` tiddler as the body-template for all Global Macro tiddlers. This template looks like:
```
<pre><code language={{!!type}}><$view field="text"/></code></pre>


```

Which is a bit overkill, but is exactly how, internally, the `application.javascript` tiddlers are rendered. But this means I no longer have to click edit on every Macro tiddler just to re-read it for bug, etc. I'm going to expand this technique to render other custom tiddler types for other projects.

Oh, yes, final note. The Type field can and will definitely over-ride this custom rendering, as that's done internally using the wiki's Parser methods. Also, I'm not sure if this is 100% backwards compatible, but the only thing I can possibly think of it changing are the Numeric Values output by the Qualify Macro (as these depend on how many and which tiddlers the current content is being rendered "through").

I think I will expand this to allow for a tabbed interface in the Draft Mode UI, with the standard Text Editor in one tab, and other content in other tabs. I can also use this to extent the Title field to allow for a custom Name (short & human readable, see plugins) that will display full size (if present) and which pushes the full Title down to a line of smaller text.

Best,

Joshua Fontany

Saq Imtiaz

unread,
May 24, 2020, 4:42:15 PM5/24/20
to tiddly...@googlegroups.com
I'm still a bit under the weather so not thinking with the clearest head here but a few thoughts:
  • I like the use of subfilter, that is the problem with the current way $:/config/ui/ViewTemplate is used, it is a direct assignment as a text reference
  • I would want similiar extensibility for other parts of the templates and not just the body. 
  • Could we tweak how we use $:/config/ui/ViewTemplate in $:/core/ui/PageTemplate/story to also allow subfilters, allowing us to use filters in that tiddler?  template={{{ [subfilter{$:/config/ui/ViewTemplate}] }}}
Hope some or any of that is helpful!
Saq

Joshua Fontany

unread,
May 24, 2020, 7:06:40 PM5/24/20
to TiddlyWikiDev
Yes, I think we can use this modification in all of the tiddler ViewTemplate/EditTemplate sections.

I like the idea of using it for $:/config/ui/ViewTemplate itself.... hmm, some way to debug things would be good, because this opens things up to a lot of possible ways to mess thing up. Maybe a new tab or section in $:/Config to toggle transcluding the template tidders VS just outputing their name as a link (so you can "jump to the code" if it is not rendering correctly by toggling the Debug switch and clicking a template title).

Thanks Saq, I'll put together a set of change as a PR, so we can have some testable code and references to clean the idea up a bit.

Best,
Joshua F

Joshua Fontany

unread,
May 25, 2020, 3:56:37 AM5/25/20
to TiddlyWikiDev
Oooooh, wow. This is incredibly powerful.

PR is up. I have attached a *.json bundle with the tiddlers I am using to test the rendering. 
The Title and Subtitle overrides have a `name` field, like a plugin, and this triggers a custom view template for each that pushes the title into the subtitle, and renders the Name in the <h2>title</h2>. Both obey the Titles-a-Links setting in $:/Config > Settings.

I have also attached a *.json bundle with just the changed shadow-tiddlers, so you could actually try this out on tiddlywiki.com by dragging both to a tab with it loaded.

https://github.com/Jermolene/TiddlyWiki5/pull/4681

Best,
Joshua Fontany
custom_templates_test_tiddlers.json
custom_templates_shadow_tiddlers.json

Saq Imtiaz

unread,
May 25, 2020, 6:02:36 AM5/25/20
to TiddlyWikiDev
I have some tiddlers that use UUIDs that are not human-readable and have a readable name in another field. So this is the exact use case for which I wanted this extended beyond just the body field. Similarly I also have a custom tags implementation in the view template....

Not to mention another wiki in which I completely replace the tiddler UI for certain tiddlers.

I will adopt this whether the pull request gets merged or not, thanks Joshua.

Joshua Fontany

unread,
May 25, 2020, 10:58:56 PM5/25/20
to TiddlyWikiDev
Here is a json of all the tiddlers necessary to test this out, both the changed sysetem tiddlers, and the custom templates and settings tiddlers I have been using to test this new system. If you drag everything into a fresh wiki, and then open the "Adat 1" tiddler, you should see that the Fields section is now in a toggle-able hidden $reveal widget, there is a toggle link/$button floating to the right of the Type field, and the BODY has two TABS - one with the normal Edit Text stuff, the other with my custom Languages fields for the glossary I am building.

Best,
Joshua F
custom_templates_edit_test.json

Mat

unread,
May 26, 2020, 4:22:56 AM5/26/20
to tiddly...@googlegroups.com
Joshua, indeed exciting. The $:/config/ui/ViewTemplate/body is like a central UI to declare which templates to show.

As you noted somewhere, it particularly makes it easier to make default templates not show and I would think your method is more system efficient than using e.g "conditional viewtemplates" (i.e tag $:/tags/ViewTemplate and with a conditional listfilter) which would be evaluated for every tiddler.

One issue: Just looking at a tiddler, it can be difficult to understand where content comes from, e.g if a tiddler "Adat" says "asfd" but there's not even a clue in Edit where this comes from. Maybe the tiddler Info, could somehow show which templates are being used?

Following with interest.

<:-)

PMario

unread,
May 26, 2020, 5:12:28 AM5/26/20
to TiddlyWikiDev
Hi,

That's an interesting approach. ... I did a very short 2 minute test. ... So I'm not really sure how everything works.

----------- Just some thoughts

At the moment the TW ViewTemplate and EditTamplates are "stackable" and changeable, without modifying the core tiddlers.

That means, If I want to create a new element, that is part of the existing UI, I only need to tag a tiddler $:/tags/ViewTempate and it will be added at the end of the list.

If I want it to be on a different position I need to add the field named: list-before or list-after.

IMO this type of functionality needs to stay. It needs to be possible, to use whatever is active and only apply the "differences" to the elements I want to change.

---------


At the moment ViewTemplate/title also contains the tiddler-toolbar. I think this is wrong. It should be at least 2 independent elements.

So if we change basic the core UI elements, we should make it even more flexible.

-mario



TonyM

unread,
May 26, 2020, 8:33:19 PM5/26/20
to TiddlyWikiDev
Mario,

As you say the view template sets all the elements tagged with $:/tags/ViewTemplate from title to subtitle, buttons etc...

There are cases when we want to alter one of these only, such as the body, there are other times we want to add or remove one or more items, often conditionally/programmatically.

When altering only the body we do not want the standard body to display so we want to replace it, on other occasions we may want to add something but hide-body conditionally/programaticaly.

I think we need a little more flexibility here. 

  • Another view template case is in a tabs internal navigation as an example, we may want to hide only the subtitle and control buttons to view tiddlers within tiddlers.
  • Also I see value in displaying alternate story's inside other tiddlers (with alternate viewtemplates), then choosing to make it the current story, eg a project story.
  • It seems to me we may need to enhance the way view and Edit templates are nominated, via both field or variable in addition to tags.
  • Perhaps we could use different templates for read-only view update and edit with a global or local tiddler override settings. I code this myself but core support would be smart and very few bytes would be needed. It would simply provide a mechanism.
Regards
Tony

Joshua Fontany

unread,
May 27, 2020, 2:01:06 AM5/27/20
to TiddlyWikiDev
Hi everyone,

Let me explain the method I am using to do these custom templates. I am not changing the existing $:/tags/ViewTemplate or $:/tags/EditTemplate architecture at all. The $list widget that builds each tiddler in the story-river still does exactly that. What I have done is gone into key system tiddlers with those  tags and found the "bare minimum" code used to render the content, moved that to a macro, such as `\define tiddler-body-default()`. Then, in that place in the system-tiddler, I put (cutting out the debug and "missing tiddler" fail-safe code):
<$list variable="sectionTemplate" filter="[all[current]subfilter{$:/config/ui/ViewTemplate/body}]" emptyMessage=<<tiddler-body-default>> >

<$transclude tiddler=<<sectionTemplate>> >
<$/list>


This checks the $:/config/ui tiddler specified for a series of filters, and uses those titles as sections. BY DEFAULT this will return empty and place the original code back using the `emptyMessage` parameter. Because the list hosting these `sectionTemplates` exist in the tiddler defining the <<tiddler-body-default>> definition, I can use that macro anywhere in my own templates to render the default __whatever__, be that into a tab, a $reveal widget, a new <$div> with a specific class or id value that is a filtered translcusion (triple braces), etc. So I can insert or hide/show the default chunk of code within my own templates. So my glossary template tiddler is as simple as:

<<tiddler-body-default>>

<
<glossary-item>>

The <<tiddler-body-default>> code is defined within the $:/tags/ViewTemplate "body" tiddler, and the <<glossary-item>> code is defined in a global macro tiddler ($:/tags/Macro) because I re-use it in other templates.

Because we are using the `subfilter{configTiddler}` operator, each filter run in that config tiddler gets fed the <<currentTiddler>> value. Then, the output is collected and returned as a title-list. This is used to render the new UI for that section. The use of filters allows __whatever__ custom triggers, conditionals, etc, you can conceive by using the current filter operators. I am currently using the existence of a tag for both the Glossary and $:/tags/Macro custom bodies. I will be building UI for my Youtube, Vimeo, etc bookmarks to transclude their player-embed code by grabbing the right parts from their link URL, and drive that on [tag[Bookmark]regexp:url<youtube-domain>], or [tag[Bookmark]regexp:url<vimeo-domain>], or whatever.

I realize now that one of the things that sparked this idea was listening to Jeremy on one of the tiddly-hangout videos talk about how robust the filter operator "language" has become now, and that many things in the core that were done in other ways could be revisited using Filters as the primary syntax. This plus seeing some of the really cool stuff being developed recently, and getting a better sense of how TW renders things "under the hood". Thanks for trying this out, and for all the feedback so far!

Best,

Joshua Fontany

Saq Imtiaz

unread,
May 27, 2020, 2:06:08 AM5/27/20
to TiddlyWikiDev
I have been using the subfilter in the page template part of this for a few months and it works great, but that's just for switching out entire templates. This allows more fine-grained control.

I expect this change to be entirely backwards compatible. The only thing worth verifying is if the qualify states have changed. I expect not as there are no extra transclusions in the default behaviour.

@pmario the ability to add templates via tags still remains.

TonyM

unread,
May 28, 2020, 3:17:19 AM5/28/20
to TiddlyWikiDev
Joshua,

This seems like a great addition. But perhaps I can clarify this from a regular users perspective? I also follow it with a Question.
Please tell me if I understand and my description is appropriate.

Description
Alternative Templates for View and Edit template sections.

The Config tiddlers such as Tiddlers $:/config/ui/ViewTemplate/body and $:/config/ui/EditTemplate/body (more below) 
Can contain zero or more additional filters of the form;

[condition[then[templatename]]


Eg
[tag[Glossary]then[templatename]]

If one or more conditions generate a template name that template (those templates?) will be uses to display that "section" of the view Template. If not the default  $:/core/ui/ViewTemplate/body will be used.
  • For example filters in $:/config/ui/ViewTemplate/body will determine an alternate template to use for the View Template Body
  • It make sense then that the templatename used should be similar to the section it replaces eg $:/owner/glossary/ViewTemplate/body
  • Perhaps the most common change will be that of the display of the body in tiddlers, with additional elements being added to tiddlers with the current tags.
Standard View and Edit Template sections (for the record)



New conditional template filters (for the record)

  1. $:/config/ui/ViewTemplate/title
  2. $:/config/ui/ViewTemplate/subtitle
  3. $:/config/ui/ViewTemplate/body
  4. $:/config/ui/EditTemplate/body
  5. $:/config/ui/EditTemplate/type
  6. $:/config/ui/EditTemplate/fields

Question: Please consider
  • To introduce a new template one needs to append another filter to that in one of the config tiddlers.
  • To reverse this one needs to not the exact filter and delete only that line.
  • Unlike the tag method used on the view and Edit templates to add new elements the order may be important but not easy to change, at least programaticaly.
  • There is a strong possibility of one solution hitting another
The Question:
  • I believe restoration of the ability to add and remove templates programaticaly through filters must be developed, Do you agree?
In Closing:
  • I have a few easy and elegant methods to enhance this mechanism to address the Question I have raised, can I ask you to collaborate on making this a little more robust?
Regards
Tony

Saq Imtiaz

unread,
May 28, 2020, 1:23:23 PM5/28/20
to TiddlyWikiDev
@Tony can you please post a precise example - with code or even pseudo code - of something you would wish to achieve, that you think is not possible with the given pull request?

Regards,
Saq

Joshua Fontany

unread,
May 28, 2020, 1:37:33 PM5/28/20
to tiddly...@googlegroups.com
I think Tony has identified the one small "weakness" in the overall design, that it is run from a single config tiddler, and if it is adopted in the core and widely used, there may be "clashes" where plugins both have the config tiddler defined. The question of adding or ordering template "chunk" filters to the config tiddler isn't as big of an issue, as each filter run can be manipulated with the list-ops filter operators to reorder (if people want a UI for that its possible).

Would it be a better idea to collect the template filters via a tag? We could extend the "parent" tag, so for `$:/tags/ViewTemplate`, we could have all body-section filter-tiddlers tagged `$:/tags/ViewTemplate/config/body`. Then we would have to collect all of the filters into a variable before passing it to the `subfilter<configFilters>` operator.

This would allow a using the more familiar tag-based ordering if multiple config tiddlers are defined and users would not have to re-order filters _within_ a config tiddler to change things at the 'section' level.

Best,

Joshua Fontany

Saq Imtiaz

unread,
May 28, 2020, 2:12:45 PM5/28/20
to TiddlyWikiDev
Two quick thoughts:
- I fear adding anymore complexity to the template logic is going to result in this being deemed plugin territory and not suitable for the core. I might be wrong, but past experience makes me cautious. Right now I see the pull request as adding a few hooks for more extensibility that is hopefully backwards compatible, rather than introducing a new core mechanism which adds complexity and probably breaks backwards compatiblity.
- A user that wanted to could still introduce tag based logic in their config tiddlers.

I haven't had the chance to think about it this in a lot of detail so I may be missing something, hence the request for a concrete example.

Joshua Fontany

unread,
May 29, 2020, 9:41:05 PM5/29/20
to TiddlyWikiDev
I appreciate the wariness at adding more complexity, this has turned out to be pretty complex already... 

I took a stab at this, and collecting a set of filter runs from multiple tiddlers based on a tag and then getting them all to behave for the `subfilter<templateFilters>` operator is very brittle (breaks easily).

My mod allows you to conditionally over-write the basic contents of certain templates - and that was not possible without completely overwriting the whole template shadow tiddler previously. I think I can extend the `subfilter[]` operator to accept a suffix, like `subfilter:tag[$:/config/ui/ViewTemplate/body]` to run through it "behind the scenes."

This keeps the wiki-text changes to the core ViewTemplate/EditTempalate tiddlers minimal, instead of adding more nested $wikify widgets or whatever. I think this is worth it because it leverages an existing concept in the user's mind, that "tag order controls tiddler-template-section rendering order".

I am sketching out a design for an RPG Campaign manager, and I really want it to be able to support both "localization", and the display of multiple game-system's "character sheets" for a single "Character tiddler". This is a complex problem, but I think we're approaching a good solution. I would want it to be flexible enough that if a user starts with one ruleset installed, they can install other ruleset/UI packages and also customize their wiki's own tiddler-UI, and not worry about manually resolving clashes.

Lets see what I can do with the `subfilter[]` operator. :D

Best,
Joshua F

PMario

unread,
May 30, 2020, 2:22:33 AM5/30/20
to TiddlyWikiDev
Hi,

No wikify widgets in Templates! If you need to concatenate strings, you need to do it the standard way. Wikify widget should be the last way, if no other possibility exists,

-m

TonyM

unread,
May 30, 2020, 5:26:34 AM5/30/20
to TiddlyWikiDev
Joshua

You are wise to be careful but complexity also supports flexibility. Of course with maturity of a concept we aim for simplicity and flexibility.

What you have identified the flexibility we want. Now the trick is simplicity.

I'm following with "baited breath"

tony

Joshua Fontany

unread,
May 30, 2020, 1:00:01 PM5/30/20
to tiddly...@googlegroups.com
@pmario, yeah, lol. No wikify widgets in commonly used rendering code!

Actually it was fairly easy to modify the subfilter oerator to do all of the logic "behind the scenes" to collect the filter runs. Its working really really well so far. Debugging when things go wrong (all titles disappeared,  etc) is a bit wierd, so I added a tag pill of the tid driving the sections-list to the "debug view". You can literally just turn on Debug, drag the tagpill's list items around and see your custom templates reorder themselves in real time. Its neat!

Unfortunately this adds 5 tag pills with long titles to the ViewTemplate... on every open tiddler. This is Not Good, (lol)... so I am cleaning up the hooks.

I will move all of that to the Advanced Tab of the Tiddler Info panel, and maybe have a way to visualize/click-to-edit/debug sections of individual open tiddlers.

May have something worth testing later :).

Best,
Joshua F

--
You received this message because you are subscribed to a topic in the Google Groups "TiddlyWikiDev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/tiddlywikidev/1OeWQD-HccU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to tiddlywikidev+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/tiddlywikidev/426063a3-7903-474e-b798-fbca0ea23b6e%40googlegroups.com.

Joshua Fontany

unread,
Jun 1, 2020, 4:16:25 PM6/1/20
to TiddlyWikiDev
Oh wow, this is working really really well.

Here is a JSON with the following tidders to test this. Because I have changed the `[subfilter[]]` operator, you would need to save and restart the test-wiki.

Test tiddlers (to remove these from your wiki, just copy/paste this list into the Filter tab of Advanced Search, the select Delete):

$:/core/modules/filters/subfilter.js
$:/core/ui/EditTemplate/body
$:/core/ui/EditTemplate/body
$:/core/ui/EditTemplate/controls
$:/core/ui/EditTemplate/fields
$:/core/ui/EditTemplate/tags
$:/core/ui/EditTemplate/title
$:/core/ui/EditTemplate/type
$:/core/ui/PageTemplate/story
$:/core/ui/TiddlerInfo/Advanced
$:/core/ui/TiddlerInfo/Advanced/TemplateInfo
$:/core/ui/ViewTemplate/body
$:/core/ui/ViewTemplate/plugin
$:/core/ui/ViewTemplate/subtitle
$:/core/ui/ViewTemplate/tags
$:/core/ui/ViewTemplate/title
$:/themes/tiddlywiki/vanilla/base
$:/plugins/joshuafontany/silatglossary/config/ui/ViewTemplate/body/macro
$:/plugins/joshuafontany/silatglossary/config/ui/ViewTemplate/title
$:/plugins/joshuafontany/silatglossary/config/ui/ViewTemplate/subtitle
$:/plugins/joshuafontany/silatglossary/ui/ViewTemplate/body/macro
$:/plugins/joshuafontany/silatglossary/ui/ViewTemplate/title/named
$:/plugins/joshuafontany/silatglossary/ui/ViewTemplate/subtitle/named

CustomTemplateTiddlers.json

TonyM

unread,
Jun 1, 2020, 9:48:23 PM6/1/20
to TiddlyWikiDev
Josha,

Thanks for this. I have added the filter 

[object-template[internal]then[$:/plugins/joshuafontany/core/ui/ViewTemplate/body/macro]]

Then tried

[all[current]object-template[internal]then[$:/plugins/joshuafontany/core/ui/ViewTemplate/body/macro]]

I then have a tiddler with the object-type field set to internal

It does not work, am I missing part of the configuration?

In Comparison this is working;

[tag[$:/tags/Macro]then[$:/plugins/joshuafontany/core/ui/ViewTemplate/body/macro]]

Thanks in advance
Tony

Joshua Fontany

unread,
Jun 1, 2020, 10:40:17 PM6/1/20
to TiddlyWikiDev
Hi Tony,

I apologize, I changed the titles of some of my system tiddlers while refactoring this. I just tested this with the correct Template system tiddler (I changed "core" to "silatglossary"), and it works!

`[object-template[internal]then[$:/plugins/joshuafontany/silatglossary/ui/ViewTemplate/body/macro]]`

Best,
Joshua F

TonyM

unread,
Jun 2, 2020, 12:22:05 AM6/2/20
to TiddlyWikiDev
Josua,

Thanks I will review this again. I must add I find that naming confusing. Could the 
$:/plugins/joshuafontany/silatglossary/ui/ViewTemplate/body/macro]]
be renamed $:/config/view-body-filters or something easier?

I do think this has awesome potential.

Regards
Tony

Joshua Fontany

unread,
Jun 2, 2020, 12:26:00 AM6/2/20
to tiddly...@googlegroups.com
Of course. Change the title of the template tiddler to whatever you would like, and update the filter to match. The test filters & templates are coming from a specific wiki I am in the middle of adding a lot of data to, so that is where I am testing.

Best,
Joshua F

--
You received this message because you are subscribed to a topic in the Google Groups "TiddlyWikiDev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/tiddlywikidev/1OeWQD-HccU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to tiddlywikide...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/tiddlywikidev/e50428d9-b4b5-4bc6-9c0c-b203619e2f28%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages