Delete all user defined fields

Hallo, there’s something that’s causing me trouble.

The goal: With a single click on a button, delete all fields (except the “system-relevant” fields).
My first approach:

<$button> delete fields
<$list filter="[all[tiddlers]]" variable="tiddlername">  
<$list filter="[fields[]] -title -text -type -tags -created -author -modified -library -url -caption -status -list -version -plugin-priority -name -description -dependents -core-version -plugin-type -current-tiddler library_version -collection -modifier -creator -source -filter -revision -bag -list-after -pretitle -posttitle -icon -var -draft.title -draft.of -color" variable="fieldname" tiddler=<<tiddlername>>>  
<$action-deletefield $tiddler=<<tiddlername>> $field=<<fieldname>> />  
</$list>  
</$list>
</$button>

That works, but not well. The problem with this solution: TiddlyWiki noticeably slows down — every keystroke is delayed.

So my second approach: Separate the button and the action so that the loops are only executed after the button press.

<$button>del fields
  <$action-sendmessage $message="tm-execute-actions" $param=DeleteUserFieldsAction />
</$button>

Now the tiddler titled: “DeleteUserFieldsAction” and typed: “application/x-tiddler-dictionary”

<$list filter="[all[tiddlers]!prefix[$:/]!is[shadow]]" variable="tiddlername">
  <$list filter="[fields[]] -title -text -type -tags -created -author -modified -modifier -creator -caption -list -plugin-type -plugin-priority -core-version -dependents -library -description -name -version -url -source -bag -filter -revision -collection -status -current-tiddler -draft.title -draft.of -color -icon -var -pretitle -posttitle" variable="fieldname" tiddler=<<tiddlername>>>
    <$action-deletefield $tiddler=<<tiddlername>> $field=<<fieldname>> />
  </$list>
</$list>

The problem here: Nothing happens. Am I missing something? Is there a better/easier solution?

Are you assuming the [fields[]] operator is working on only the tiddler from the outer list? That would be incorrect.

The number of items in the final list is going to the number of [all[tiddlers]] times the number of all fields in the wiki. This could be a large number.

Try using [<tiddlername>fields[] - text -title ... to narrow it down.

There is probably a smarter way to accomplish this but I’ll leave it up to one of the experts on the forum.

My initial thought would be to reverse the order of the lists. Something like this:

<$list filter="[fields[]]" variable=fieldname>
  <h2><<fieldname>></h2>
  <$list filter="[has<fieldname>]">
      <li><$link/></li>
  </$list>
</$list>

1 Like

The reason, of course, is that so long as the tiddler with the button is rendered, on every change, the core will need to reevaluate the nested lists, both quite long.

If you move the activity into a procedure, and call that procedure as the action parameter of your button, you will only evaluate the lists on click:

\procedure delete-fields()
  <$list filter="[all[tiddlers]]" variable="tiddlername">  
    <$list filter="[fields[]] -title -text -type -tags -created -author -modified -library -url -caption -status -list -version -plugin-priority -name -description -dependents -core-version -plugin-type -current-tiddler library_version -collection -modifier -creator -source -filter -revision -bag -list-after -pretitle -posttitle -icon -var -draft.title -draft.of -color" variable="fieldname" tiddler=<<tiddlername>>>  
      <$action-deletefield $tiddler=<<tiddlername>> $field=<<fieldname>> />  
    </$list>  
  </$list>
\end delete-fields

<$button actions=<<delete-fields>> > delete fields</$button>

And I finally realize the reason experienced people have been pushing “action strings”! These delay rendering of the contents of the button until its actually needed. Sometimes I can be dense, I guess.


For the list of fields to delete, you might look at an earlier discussion about this. I was pretty happy to come up with this filter:

[fields[]] -[all[shadows]removeprefix[$:/language/Docs/Fields/]]
2 Likes

@Scott_Sauyet makes an excellent point about keeping your button actions in an actions string so the filters are only run when you actually click the button — and it sounds like you had that instinct, too! I’d go a step further and combine his solution with @amreus’s:

\procedure delete-fields()
<$let systemFields="title text type tags created author modified library url caption status list version plugin-priority name description dependents core-version plugin-type current-tiddler library_version collection modifier creator source filter revision bag list-after pretitle posttitle icon var draft.title draft.of color">
  <$list filter="[all[tiddlers]!is[system]!is[shadow]]" variable="tiddlername">  
    <$list filter="[<tiddlername>fields:exclude<systemFields>]" variable="fieldname">  
      <$action-deletefield $tiddler=<<tiddlername>> $field=<<fieldname>> />  
    </$list>  
  </$list>
</$let>
\end delete-fields

<$button actions=<<delete-fields>> > delete fields</$button>

I’m using [fields:exclude<systemFields>] in place of [fields[]] -fields -to -exclude because I find it easier to update the list of field names when it’s stored as an external variable, but this is a matter of preference.

  • Note that if you do use Scott’s filtered-derived list of fields, you’ll need to change systemFields=... to a filtered transclusion, and add +[join[ ]] because fields:exclude expects field names as space-separated string:
systemFields={{{ [all[shadows]removeprefix[$:/language/Docs/Fields/]] +[join[ ]] }}}

Side note:

I’m not surprised that nothing happened; tm-execute-actions isn’t a widget message I’ve ever seen in TiddlyWiki, and the application/x-tiddler-dictionary tiddler type is used for storing data in index: value pairs, not wikitext to be executed as an action. Is this a custom message you added to your wiki? Or was this code perhaps suggested by an LLM/AI chatbot?

2 Likes

Many thanks to everyone! The code is now running smoothly, and my TiddlyWiki remains fast and responsive.
Each obstacle brings new insights, though TiddlyWiki tends to be rather unforgiving when it comes to mistakes. Am I correct in assuming that any code within a procedure or function only gets executed or rendered when it is explicitly called?

@etardiff You are right: ChatGPT isn’t (yet) the most reliable source for writing scripts in TiddlyWiki.

1 Like

Sort of…

When your procedure call occurs within the actions=... param of the $button widget, the entire procedure is not processed until the button is clicked, thereby avoiding the costly $list widget evaluation when your button is refreshed.

However, if your procedure call occurs directly within the body of a $button widget, it is still invoked each time the $button widget is rendered/refreshed even though any $action widgets within the procedure are only performed when the button is clicked. Thus, the costly $list widgets are still processed each time the $button widget is rendered/refreshed.

-e

1 Like

Thanks for the clarification @EricShulman, I think this is extremely important information! Especially for larger TiddlyWikis, this can help to save a significant amount of resources.
So I have to check all my procedures.

1 Like

You have a good solution to your direct question.

But I almost always want to ask: What is your workflow behind such an unusual request? How is it that you are frequently creating fields and then needing a button to get them deleted?

I wonder whether having a button to delete fields is actually the most straightforward way of doing the kind of task that you’re up to…

In particular, I wonder whether you would benefit by putting some of your non-permanent data into tiddlers in the $:/temp/ namespace — which would not be saved at all. Or maybe there’s some other way in which your solution could be “smart” about what’s retained, and what’s deleted, so that it’s doesn’t require going around and pressing buttons on a regular basis. :slight_smile:

Feel free to ignore my question if you’re simply poised to power ahead with what you’ve got! But this community can often help people think big-picture about the structure of their data. This might free up more of your time/attention for an efficient workflow.

3 Likes

Thank you @Springer for your interest. I’ve actually been using TiddlyWiki as a kind of typesetting system for over 10 years now. A detailed description and examples of an earlier version can be found here:

https://texter.tiddlyhost.com/

A lot has changed since then. For instance, I’m increasingly using the modal features, which are much more convenient.

“Texter” is incredibly helpful to me when creating reports, something I need to do several times a day. These reports and findings tend to follow a similar structure, are modular in design, and differ only slightly within the various interchangeable text blocks. To handle this efficiently, I need the individual text blocks as Tiddlers, and within them temporary text snippets which — it seemed simplest to me — are stored in the fields. The current select macro looks like this:

Tiddler Title: select
Tag: $:/tags/Macro

\define select(var)
\whitespace trim
{{$var$||$:/core/ui/TagTemplate}} <$select field='$var$'>
<$list filter='[tag[$var$]]'>
 <option value={{!!text}}><$view field='title'/></option>
</$list>
</$select>
<$button>
  {{$:/core/images/new-here-button}}
  <$action-sendmessage $message="tm-modal" $param="selectitem" tagname=$var$ />
</$button>
<$button>{{$:/core/images/delete-button}}<$action-deletefield $tiddler=<<currentTiddler>> $field="$var$"/></$button>
<mark>{{!!$var$}}</mark>
\end

The corresponding modal looks like this:

Tiddler Title: selectitem

<$edit-text tiddler="$:/temp/newTiddlerTitle" tag="input" default=""/>

<mark><<tagname>></mark>

<!--{{<<tagname>>||$:/core/ui/TagTemplate}} REM doesn't work, I don't know why -->

<$edit-text tiddler="$:/temp/newTiddlerText" tag="textarea" minHeight="300" default=""/>

<$button>
Save
<$action-createtiddler $basetitle={{$:/temp/newTiddlerTitle}} tags=<<tagname>> text={{$:/temp/newTiddlerText}}/>
<$action-deletetiddler $tiddler="$:/temp/newTiddlerTitle"/>
<$action-deletetiddler $tiddler="$:/temp/newTiddlerText"/>
</$button>

It is called, for example, with: <<select Operation>>

Finally, my two cents: There is nothing on the market — including PhraseExpress, Text Blaze, TextExpander, aText, … — that comes close to the capabilities of TiddlyWiki when it comes to working with complex “text setting”. I’m convinced that TiddlyWiki holds an as-yet largely untapped potential in this area (eg. legal contracts, medical findings, appraisals or certificates.).

Perhaps I need to clarify: it’s the status of the select macro that is stored in a field, not the text snippet itself. Since there are many such insertions in the texts, with their status stored in fields, I want to delete all of them at once. That’s why I made the above request.

I’m still further intrigued by your workflow using this. I recall seeing this when you posted some months back, and while I don’t have a use for it myself, I do find it fascinating.

But I’m curious: Do you do a single wiki per report? A single wiki per patient? Is the delete-all-fields meant to happen when you clone an empty report, because some detritus might have snuck in? Or is it more heavy-weight?

I worry about the approach, as I would expect in any significant wiki to have many fields for many reasons, a lot of them not actually related to your fill-in mechanism. It would feel like a straight-jacket to deny myself the ability to use custom fields for other purposes. Might it make sense to proactively identify the fields you would want to delete, perhaps all fields with the prefix fi- (for “fill-in”) or something similar? (And of course it may not. I have a sense of the technical details of texter, but little of how you’re using it.)

1 Like

Right — my sense is that if I’m compiling something, I would want not simply a copy-paste utility, but an archive of each thing I’ve done. (Someone says, “hey could you please change this one date detail and this one legal name typo on that compiled report from last week?” and… all the info was deleted after use, so start from scratch?)

I’d have a tiddler for each actual compilation, including metadata (for whom, created on what date, with what template, etc., with fields for each variable established for that report/output). It shouldn’t be too hard to create a button to put the text on the clipboard by the way. I don’t have time at the moment, but I have various dynamic “copy to clipboard” interfaces…

Then, you don’t have to delete fields — just create a new tiddler when you’re ready to compile another complex thing.

Very impressive interface, though, @96eron ! I also enjoyed the literary references. It’s a fun demo!

(Also, since “texting” as a verb is so associated with SMS messaging, and “typesetting” is a phrase from… letterpress printing (!), I’d think the natural verb in English is compiling or composing or report-customizing… even merging (thinking of old MS Word “mail merge” which was kind of like this).)

1 Like