[TW5] How to create a button that replaces a field value based on the current field value?

1,134 views
Skip to first unread message

Antaeus Feldspar

unread,
Oct 3, 2015, 1:49:00 PM10/3/15
to TiddlyWiki
Or, to express it a different way from the subject line, how can I create a button widget that will:
a) take the current value of a tiddler field;
b) use that current value as a parameter to a macro to calculate a new value; and
c) put that new value back into the tiddler field that was read?

WHAT I TRIED:

I've tried various things; my most recent attempt is this:

<$button set=!!test setTo=<$macrocall $name=".js-macro-link" text={{!!test}}/> >Test button</$button>

However, the parser can't seem to handle the angle brackets of the macrocall widget appearing in the middle of the button widget declaration. Everything after the "/>" that closes the macrocall widget appears as WikiText following a blank button.

Before that I tried calling the macro through the standard syntax, and discovered that (unless there's some way to do it that I missed) you can't use a macro call as an element attribute.

It occurred to me that since a ButtonWidget can contain multiple ActionWidgets, that might be the solution - except that there's nothing in the documentation guaranteeing an order in which such widgets execute, so assigning the output of a macro to a temporary tiddler and then copying it back to the original field does not seem to be an option.

PLEASE NOTE:

Please note that I am trying to get an answer to the GENERAL question, not "how do I get the same effect as if I was applying this particular macro?" I am sure that there would be a simple way to apply the effect of THIS macro with template transclusion, but that does not answer my question, because sooner or later I will be using the technique for Javascript macros that do mathematical calculations.

DOCUMENTATION SUGGESTION:

A chart which shows the various forms of data sourcing (plain text, TextReference, macro output, etc.) in columns and then shows in rows what they can and can't be used for (macro parameters, element attributes, etc.) would be useful.

Tobias Beer

unread,
Oct 3, 2015, 3:34:31 PM10/3/15
to TiddlyWiki
Hi Antaeus,

One (perhaps) clumsy way to go about it would be
to not try and pass a ("text") parameter to your inner macro,
but rather set a variable outside of all that via the SetWidget,
so you could then do...

<$set name="js-macro-link-text" value={{!!test}}>
<$button set=!!test setTo=<<js-macro-link>>>Test button</$button>
</$set>

Best wishes,

— tb

Mark S.

unread,
Oct 3, 2015, 3:41:08 PM10/3/15
to TiddlyWiki
Hello,

What I've found so far is:

1) Macros and widgets may look something like javascript functions and variables, but they often behave differently
2) You can't use a widget's output inside a widget
3) You can use a macro inside a widget IF it doesn't have a parameter
4) Therefore, you will most often need to use <$set ...> to set a variable to be used by a macro that gets fed to your widget

Mark

Tobias Beer

unread,
Oct 3, 2015, 4:49:51 PM10/3/15
to tiddl...@googlegroups.com
 Hi
 
4) Therefore, you will most often need to use <$set ...> to set a variable to be used by a macro that gets fed to your widget

Not much of a fan of this part either.
At least, the VarsWidget is providing some relief on that.

Best wishes,

— tb 

Antaeus Feldspar

unread,
Oct 3, 2015, 5:53:12 PM10/3/15
to TiddlyWiki
Tobias, Mark, thank you for your suggestions... The use of SetWidgets to set variables is something I didn't understand before, and I can tell I'll eventually be able to use it to achieve a much cleaner solution.

Right now, though, I still have a problem that's completely blocking me: how do I get the *results* of a macro call into a variable?

The project I'm working on will involve dates. I can write a macro in Javascript which takes a date in TW's format and adds or subtracts a given amount of time. But how can I have TiddlyWiki call that macro *and* store it in a field rather than simply rendering the result on the screen?

Antaeus Feldspar

unread,
Oct 3, 2015, 6:23:44 PM10/3/15
to TiddlyWiki
By the way, if macros with parameters don't work as widget attributes... does that mean that the last example shown for the MacroCall Widget doesn't actually work?

From http://tiddlywiki.com/#MacroCallWidget :

<$macrocall $name="italicise" text=<<textMaker "Another macro to generate the text to be italicised">>/>

Does this not work, and it got included as an example without testing? Or, if it does work, why does it work when other attempts to use macros as attributes fail?

Jeremy Ruston

unread,
Oct 3, 2015, 6:31:53 PM10/3/15
to tiddl...@googlegroups.com
Hi Mark

3) You can use a macro inside a widget IF it doesn't have a parameter

That is not correct. Macro invocations used as widget attributes may have parameters.

However, there are a couple of points to watch:

* The output of the macro is not wikified; it is used directly as the value of the attribute
* The double angle brackets widget call syntax only allows parameters to be specified as strings

Best wishes

Jeremy.

4) Therefore, you will most often need to use <$set ...> to set a variable to be used by a macro that gets fed to your widget

Mark

On Saturday, October 3, 2015 at 10:49:00 AM UTC-7, Antaeus Feldspar wrote:
Or, to express it a different way from the subject line, how can I create a button widget that will:
a) take the current value of a tiddler field;
b) use that current value as a parameter to a macro to calculate a new value; and
c) put that new value back into the tiddler field that was read?

WHAT I TRIED:

I've tried various things; my most recent attempt is this:

<$button set=!!test setTo=<$macrocall $name=".js-macro-link" text={{!!test}}/> >Test button</$button>

However, the parser can't seem to handle the angle brackets of the macrocall widget appearing in the middle of the button widget declaration.  Everything after the "/>" that closes the macrocall widget appears as WikiText following a blank button.

Before that I tried calling the macro through the standard syntax, and discovered that (unless there's some way to do it that I missed) you can't use a macro call as an element attribute.

It occurred to me that since a ButtonWidget can contain multiple ActionWidgets, that might be the solution - except that there's nothing in the documentation guaranteeing an order in which such widgets execute, so assigning the output of a macro to a temporary tiddler and then copying it back to the original field does not seem to be an option.

PLEASE NOTE:

Please note that I am trying to get an answer to the GENERAL question, not "how do I get the same effect as if I was applying this particular macro?"  I am sure that there would be a simple way to apply the effect of THIS macro with template transclusion, but that does not answer my question, because sooner or later I will be using the technique for Javascript macros that do mathematical calculations.

DOCUMENTATION SUGGESTION:

A chart which shows the various forms of data sourcing (plain text, TextReference, macro output, etc.) in columns and then shows in rows what they can and can't be used for (macro parameters, element attributes, etc.) would be useful.











-- 
You received this message because you are subscribed to the Google Groups "TiddlyWiki" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tiddlywiki+...@googlegroups.com.
To post to this group, send email to tiddl...@googlegroups.com.
Visit this group at http://groups.google.com/group/tiddlywiki.
To view this discussion on the web visit https://groups.google.com/d/msgid/tiddlywiki/b9f31e05-bf09-4170-a63e-5e57225f3cc0%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Mark S.

unread,
Oct 4, 2015, 12:52:18 AM10/4/15
to TiddlyWiki
Apparently you can use static text. But this is of limited value IMO. What you want is something more like <<textMaker {{!!myField}}>> .

I just know whenever I've tried making a bit of simple widget code work with some macros, I usually end up needing to use <$set>.

Mark

Mark S.

unread,
Oct 4, 2015, 1:11:35 AM10/4/15
to TiddlyWiki
Hi Jeremy,

But, at the bottom line, is there any way to set up Tobias' solution without resorting to <$set> (or <$var>) ?

Thanks!
Mark

Jeremy Ruston

unread,
Oct 4, 2015, 5:18:40 AM10/4/15
to tiddl...@googlegroups.com
Hi Mark

As you’ve discovered, this doesn’t work:

<<textMaker {{!!myField}}>>

Instead, you can use the <$macrocall> widget to invoke the macro. For example:

<$macrocall $name=“textMaker” myParam={{!!myField}}/>

Widgets are the fundamental unit of functionality in TiddlyWiki; all the other wikitext syntax is just shortcuts for creating widgets.

But, as discussed before, one can’t use that syntax as an attribute value.

Best wishes

Jeremy

--
You received this message because you are subscribed to the Google Groups "TiddlyWiki" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tiddlywiki+...@googlegroups.com.
To post to this group, send email to tiddl...@googlegroups.com.
Visit this group at http://groups.google.com/group/tiddlywiki.

BJ

unread,
Oct 4, 2015, 8:14:48 AM10/4/15
to TiddlyWiki
Hi Antaneus,

you ca
this.getVariable("
You should be able to use Tobias suggestion


<$set name="js-macro-link-text" value={{!!test}}>
<$button set=!!test setTo=<<js-macro-link>>>Test button</$button>
</$set>
In your javascript macro you can read the value of "js-macro-link-text" like so:

var input = this.getVariable("js-macro-link-text");

cheers

BJ

Antaeus Feldspar

unread,
Oct 4, 2015, 11:00:56 AM10/4/15
to TiddlyWiki
Jeremy, could I please get your answer to my question?

What is the right way to create a button that will read a value from a field, use that value as input to a macro to reach a new value, and then write that value back to the same field?

I'm starting to get a bit discouraged that such a simple goal seems so difficult to achieve.

Am I just taking the completely wrong approach? Is there a different way, other than macros, to do calculations in JavaScript on data stored in tiddlers? If so, where is it documented?

Jeremy Ruston

unread,
Oct 4, 2015, 11:42:06 AM10/4/15
to tiddl...@googlegroups.com
Hi Antaeus

> Jeremy, could I please get your answer to my question?

I would have expected Tobias’s solution to work. Does it work for you?

> What is the right way to create a button that will read a value from a field, use that value as input to a macro to reach a new value, and then write that value back to the same field?

Only simple logic can be expressed in wikitext, so it would be reasonable to create a JS macro for more complex logic. You can also write widgets but that generally only makes sense if you want to create dom elements, trap events, or interact with the refresh process.

Best wishes

Jeremy

> I'm starting to get a bit discouraged that such a simple goal seems so difficult to achieve.
> Am I just taking the completely wrong approach? Is there a different way, other than macros, to do calculations in JavaScript on data stored in tiddlers? If so, where is it documented?



>
> --
> You received this message because you are subscribed to the Google Groups "TiddlyWiki" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to tiddlywiki+...@googlegroups.com.
> To post to this group, send email to tiddl...@googlegroups.com.
> Visit this group at http://groups.google.com/group/tiddlywiki.
> To view this discussion on the web visit https://groups.google.com/d/msgid/tiddlywiki/1a5c17b5-129a-410a-911f-ce0651b5e362%40googlegroups.com.

Tobias Beer

unread,
Oct 4, 2015, 11:59:30 AM10/4/15
to TiddlyWiki
Hi Antaeus,

I can see how a js macro might be a simpler first step but perhaps a macro isn't the best implementation for what it is you try to achieve, but rather a widget or maybe a filter operator.

Best wishes,

— tb

Antaeus Feldspar

unread,
Oct 4, 2015, 6:03:01 PM10/4/15
to TiddlyWiki
Thank you, Jeremy and Tobias especially! I have it working now!

The first time I read Tobias' solution and tried my own based on it, it didn't work for me. I don't know exactly what I was doing wrong (the text of that attempt was lost by a browser crash), but every attempt to call the macro seemed to produce just the text of the macro call, not its result.

Now I understand the solution: write the macro so that any parameters which can't be represented as hard-coded strings are instead accepted via variables. Then use SetWidgets or a VarsWidget around the macro call, and set the parameters with those. Then the macro call can be used as an attribute to the ButtonWidget.

This is the code of my working version:


```
\define add-she-said()
Hey $(add-she-said-text)$ - is what she said.
\end

<$set name="add-she-said-text" value="roll it">

----

<<add-she-said>>
</$set>

<$set name="add-she-said-text" value={{!!test}}>
<$button set=!!test setTo=<<add-she-said>>>Test button</$button>
</$set>

```

Tobias, you're right that the best solution may end up being something other than a macro, but to keep the project going, I have a deep need to be able to update certain data fields easily in great numbers of tiddlers. An imperfect solution now is tons better than a perfect solution in three months.

Tobias Beer

unread,
Oct 6, 2015, 6:15:48 AM10/6/15
to TiddlyWiki
Hi Antaeus, 

Tobias, you're right that the best solution may end up being something other than a macro, but to keep the project going, I have a deep need to be able to update certain data fields easily in great numbers of tiddlers.  An imperfect solution now is tons better than a perfect solution in three months.


Always true. What would be interesting to see is what your macro actually does, even if, perhaps, imperfectly so. ;-)

Best wishes,

— tb

Antaeus Feldspar

unread,
Oct 6, 2015, 10:30:43 AM10/6/15
to TiddlyWiki
I absolutely plan to offer it for public consumption when I have it working well. I also have some ideas for some useful filter-operators, but since I'm just getting started with the macros, the filter-operators are some distance in the future!

Antaeus Feldspar

unread,
Oct 6, 2015, 10:13:28 PM10/6/15
to TiddlyWiki
Actually, perhaps I should share what my macro will do - I went looking to see if there was an existing plugin that handled such things, and didn't find one, but that could be just because I wasn't looking in the right places.

My macro will take a 17-character string as used in a Date field as its first parameter, and as its second, a string indicating an amount of time to increment it ("1d", for instance, would be one day.) It will calculate and return the incremented date. With being able to read, modify, and write back a date values, I can create easy "reschedule" buttons for task tiddlers.

To tell the truth, there are some terrific JS libraries that do all of that and much more, and I was hoping there would be a simple way they might be incorporated into TW5, but if there is, I haven't found documentation for it. Is there such a way? Or has someone already created awesome date-manipulation plugins?

infurnoape

unread,
Oct 7, 2015, 12:58:14 AM10/7/15
to tiddl...@googlegroups.com
How about 

Happy Connecting. Sent from my Sprint Samsung Galaxy S® 5
--
You received this message because you are subscribed to the Google Groups "TiddlyWiki" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tiddlywiki+...@googlegroups.com.
To post to this group, send email to tiddl...@googlegroups.com.
Visit this group at http://groups.google.com/group/tiddlywiki.

Tobias Beer

unread,
Oct 7, 2015, 12:07:26 PM10/7/15
to tiddl...@googlegroups.com
Hi Antaeus,

There's are these core functions under $tw.utils:

parseDate — parses a datestring into a js date object
stringifyDate — does the reverse

So, something like this should do the trick of shifting by a given number of days...

function(datestring, shiftbydays) {
   
var date = $tw.utils.parseDate(datestring),
    result
= new Date(date.getTime() + shiftbydays*86400000);
   
return $tw.utils.stringifyDate(result);
}

Addendum: Or that... $:/plugin/ajh/tiddlytime/DateTime.js @ t5a ;-)

Best wishes,

— tb

Mark S.

unread,
Oct 7, 2015, 12:08:20 PM10/7/15
to TiddlyWiki
That code looks nice and clean, and might do everything Antaeus wants ... EXCEPT that it can't (or at least I don't think it can) be used inside a button the way he wants.

The solution is to rewrite the javascript code so that it accepts values from <$set> variables outside instead of parameters.

Someone could eliminate the parameters and instead put these lines just inside the run() function:
 
var format = this.getVariable("format") ;

var delay = this.getVariable("delay") ;

var ts = this.getVariable("ts") ;

I haven't tried it though. If anyone tries this, they should be sure to back up their TW. A single mistake can cause the red-block-of-javascript doom to pop up.

Mark
Reply all
Reply to author
Forward
0 new messages