toggleButton example

Hello,

While all the tweakability of the checkbox widget is great, I still wanted something similar that would change the actual graphic of the box and toggle between a “view” and “edit” mode (thus the default values). So I put the following together using examples from tiddlywiki.com that I never would have figured out on my own:

\define toggleButton(tiddler:"target" field:"mode" offValue:"view" offImage:"""$:/core/images/edit-button""" onValue:"edit" onImage:"""$:/core/images/save-button""")
<$button class="tc-btn-invisible">
<$action-listops $tiddler="$tiddler$" $field="$field$" $subfilter="+[toggle[$onValue$],[$offValue$]]" />

Option 1
<$reveal  type="nomatch" stateTitle="$tiddler$" stateField="$field$" text="$onValue$">{{$offImage$}}</$reveal>
<$reveal  type="match" stateTitle="$tiddler$" stateField="$field$" text="$onValue$">{{$onImage$}}</$reveal>

Option 2:
{{{[[$tiddler$]get[$field$]match[$onValue$]then[$onImage$]else[$offImage$]]||transclude}}}

Option 3:
<$let buttonImage={{{[[$tiddler$]get[$field$]match[$onValue$]then[$onImage$]else[$offImage$]]}}}>
<$transclude tiddler=<<buttonImage>>/>
</$let>
</$button>
\end

My questions are:
Of these three options for displaying the icon image:

  1. Is one better in some way or are they all pretty much interchangable?
  2. The transcluded filter is a nice compact way to do things but necessitates another filter tiddler named “transclude” that just has {{}} in it. Is there a built in core template equivalent that I could re-purpose? $:/core/ui/ViewTemplate/body/default seemed to be the closest but put things into block-mode and I would like to keep it inline.
  3. Is there a way to tweak the filter such that you don’t need a template? I tried using {$onImage} rather than [$onImage$] but it just burped up the SVG text as a link.

I settled on Option 3 as the one to use but I would like to hear thoughts from others and suggestions to make it more globally useful.

Thanks,
/Mike

Do you have any objection of keeping all 3 options to use as examples of alternate ways of doing it?

seeing how it can be done in different ways gives context for new users to figure out how things work, and can lend to inspiring ideas on ways they can do things.

All 3 options have a lot going on there, so I’ll give you yet another option :stuck_out_tongue:

This option won’t need to be a macro, it can just be transcluded as a template where ever you need it.

<$button
     class="tc-btn-invisible"
     setTitle=<<currentTiddler>>
     setField=mode
     setTo={{{ [<currentTiddler>mode[edit]then[view]else[edit]] }}}
>
   <$list filter="[<currentTiddler>!mode[edit]]">
      {{$:/core/images/edit-button}}
   </$list>
   <$list filter="[<currentTiddler>mode[edit]]">
      {{$:/core/images/save-button}}
   </$list>
</$button>

This should work if you want to transclude the button directly into a another tiddler or use it inside a LIST widget.

If the above code was put into a tiddler named “Btn-Modes”, you could transclude the button as {{||Btn-Modes}}. Putting the double pipes “||” in front of the tiddler title will have act as a template and pull the mode field from whatever tiddler the button is transcluded to rather than the button tiddler itself.

EDIT

To match more with your original code, I would probably do something like this:

\define toggleButton(tiddler:"target" field:"mode" offValue:"view" offImage:"""$:/core/images/edit-button""" onValue:"edit" onImage:"""$:/core/images/save-button""")
<$button class="tc-btn-invisible"
     setTitle="$tiddler$"
     setField="$field$"
     setTo={{{ [[$tiddler$]get[$field$]match[$onValue$]then[$offValue$]else[$onValue$]] }}}
>
<$transclude tiddler={{{ [[$tiddler$]get[$field$]match[$onValue$]then[$onImage$]] }}} />
<$transclude tiddler={{{ [[$tiddler$]get[$field$]!match[$onValue$]then[$offImage$]] }}} />
</$button>
\end

<<toggleButton "Button - Toggle Field Values">>

2 Likes

Hey @Brian_Radspinner, your template inspired me, here’s an evolution with variables and default values:

<!--
Transclusion template for toggle button.

Default values:
    tiddler: <<currentTiddler>>
      field: mode
   offValue: view
   offImage: $:/core/images/edit-button
    onValue: edit
    onImage: $:/core/images/save-button

You can override these values by setting variables named after the 
parameter with added prefix "tbt-" like this:

  <$let tbt-tiddler="mytiddler" tbt-field="xxx" ...>
  {{||Btn-Modes}}
  </$let>
-->
<$let
  myTarget   ={{{ [<tbt-tiddler>is[blank]then<currentTiddler>else<tbt-tiddler>] }}}
  myField    ={{{ [<tbt-field>is[blank]then[mode]else<tbt-field>] }}}
  myOffValue ={{{ [<tbt-offValue>is[blank]then[view]else<tbt-offValue>] }}}
  myOffImage ={{{ [<tbt-offImage>is[blank]then[$:/core/images/edit-button]else<tbt-offImage>] }}}
  myOnValue  ={{{ [<tbt-onValue>is[blank]then[edit]else<tbt-onValue>] }}}
  myOnImage  ={{{ [<tbt-onImage>is[blank]then[$:/core/images/save-button]else<tbt-onImage>] }}}
>
<$button
     class="tc-btn-invisible"
     setTitle=<<myTarget>>
     setField=<<myField>>
     setTo={{{ [<myTarget>get<myField>match<myOnValue>then<myOffValue>else<myOnValue>] }}}
>
   <$list filter="[<myTarget>get<myField>match<myOnValue>then<myOnImage>else<myOffImage>]">
      {{}}
   </$list>
</$button>
</$let>

You can paste above code in a tiddler named Btn-Modes and test it in another tiddler containing:

{{||Btn-Modes}} (current mode:{{!!mode}})

<$let
 tbt-field="state"
 tbt-onValue="locked"
 tbt-onImage="$:/core/images/unlocked-padlock"
 tbt-offValue="unlocked"
 tbt-offImage="$:/core/images/locked-padlock"
>
{{||Btn-Modes}} (current state: {{!!state}})
</$let>

Fred

2 Likes

Hi @mwiktowy,

Here is a 5th option, extracted from my code above where the actual values are in variables:

   <$list filter="[<myTarget>get<myField>match<myOnValue>then<myOnImage>else<myOffImage>]">
      {{}}
   </$list>

Fred

2 Likes

@Brian_Radspinner its nice to see another approach to toggle buttons, make me stop and think differently to my own approach that has become a habit.

  • I hope soon to make some “button makers” and this will help me “look outside the standard button”

I did 3 videos about a “ToggleMe” button and some variations thereof. … The videos are from 2017, but they are step-by-step instructions how to create a highly dynamic toggle-button from scratch. So IMO it can still be used as an example, how to use the TW documentation examples to get something going.

Since 2017 we didn’t have the possibilities we have now. … I do Fred’s example quite a bit, due to the clean code.

Here’s the first out of 3 videos. (23min for all 3)

Here’s the project Script Manager Edition — manage information of all types which I still use on a daily basis to keep my links and code snippets up to date.

1 Like

There some other toggle button you may like to see

https://talk.tiddlywiki.org/t/good-practice-quotes-in-scripts-single-double-or-triple-double-quotes/1620

The oldest in the field is the one by @twMat and can be found here: http://toggle.tiddlyspot.com/

1 Like

Thank you all for your ideas!

I’ve settled on:

\define toggleButton(tiddler:"" field:"mode" offValue:"view" offImage:"""$:/core/images/edit-button""" onValue:"edit" onImage:"""$:/core/images/save-button""")
<$button class="tc-btn-invisible">
<$let myTarget={{{ [[$tiddler$]is[blank]then<currentTiddler>else[$tiddler$]] }}}>
<$action-listops $tiddler=<<myTarget>> $field="""$field$""" $subfilter="""+[toggle[$onValue$],[$offValue$]]""" />
<$list filter="""[<myTarget>get[$field$]match[$onValue$]then[$onImage$]else[$offImage$]]""">
{{}}
</$list>
</$let>
</$button>
\end
<$list filter="[<currentTiddler>compare:string:eq[ToggleButton]]" variable=avoid_changing_currentTiddler>

''Usage:'' This a small macro to add a button that will toggle a title in a tiddler field between two values.

!! Parameters

;tiddler
: The tiddler name where you want the field toggled. (defaults to currentTiddler)
;field
: The field name that will contain the values. (default: mode)
;offValue
: The value that will be set when the button is turned off. (default: view)
;offImage
: The image that will be the button icon initially and when the button is turned off. (default: $:/core/images/edit-button)
;onValue
: The value that will be set when the button is turned on. (default: edit)
;onImage
: The image that will be the button icon when the button is turned on. (default: $:/core/images/save-button)

This usage information will automatically disappear if the containing tiddler is not named "ToggleButton".

</$list>

because:

  1. While the idea of poking everything into the pre-built “setTitle” “setField” “setTo” parameters of the button widget is appealing, I do like the flexibility of the action-listops widget to deal with fields containing lists like “tags” and maybe continuing to use the toggle operator will make it easier to extend to n options rather than 2 in the future. Possibly setTo could contain something that would act like the action-listops but I am going to take the option that works.
  2. I like the list widget option 5 since it seems the most concise and readable.
  3. I took some advice from @Mohammad’s post to allow it to deal with tiddlers with macro calls like <<toggleButton """Dealing with tiddler's "quotes" spaces and apostophes""" "tags">>
  4. I also incorporated the idea of defaulting to <<currentTiddler>> if no tiddler is specified. I struggled with doing so since the default values in the macro definition don’t like to contain variables but @tw-FRed examples cracked the code for me.

Thanks again for your great input.

/Mike

Edit reason: Add some documentation and robustness for field values with quotes and apostrophes.