Can I use the result of a macro in the state of the RevealWidget?

146 views
Skip to first unread message

Philippe Le Toquin

unread,
Oct 31, 2016, 6:45:29 PM10/31/16
to TiddlyWiki
Hello,

I have looking all over the place and experimented a lot but I can't find how to do what I want to achieve.

I have a list of item (they are ingredients) that contains some fields .One of them is a best before date.

I then list the ingredient using that code to display them as well as the number of days until they expire.

<$list filter="[!has[draft.of]tag[Stocks]]">

* <$link to={{!!title}}><$view field="title"/> </$link>@@color:red;( to be discarded : <$macrocall $name="day-left" bestbefore={{!!bestbefore}} />)@@

</$list>

The macro is based on day-diff.js that I modified to only take one day and return YES or NO.

What I would ideally like to do is that the text in red (to be discarded) only appears if the return of the macro is YES.

I would like to use the RevealWidget but can't make it works. Here is what I tried


* <$link to={{!!title}}><$view field="title"/> </$link> <$reveal type="match" state="<$macrocall $name="day-left" bestbefore={{!!bestbefore}} />" text="YES">@@color:red;( to be discarded )@@ </$reveal>

but the result of that is not working. Instead it displays:


<$reveal type="match" state="YES" text="YES">( to be discarded ) </$reveal>

<$reveal type="match" state="NO" text="YES">( to be discarded ) </$reveal>





So my question is : Is it possible to achieve what I want?

Mark S.

unread,
Oct 31, 2016, 7:39:53 PM10/31/16
to TiddlyWiki
Macros will drive you nuts, because they look for all the world like regular programming functions that you may encounter in any programming language. But they're not.

Since you're willing to make changes to the actual macro code, I can pass on my "trick" I've used in javascript macros. If memory serves, what I've done in similar situations is to make input and output variables in the calling environment. E.g.

<$set indate={{!!bestbefore}}.> ...
<$set outval="unused"> ...

Then inside the javascript macro, fetch the value like:

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

and after passing this to the program, return the value like:

this.setVariable("outval",whatever_the_return_variable_is) ;

Then (still inside the <$set>...</$set> tags) use the "outval" result in your reveal widget.

I don't know for sure if this will work for you, but it's the kind of thing that I've used in the past.

Remember to back up your TW before messing with javascript macros (since a crash can lock you out) and that you have refresh your TW before javascript macros will take effect.

Good luck!
Mark

Eric Shulman

unread,
Oct 31, 2016, 8:12:48 PM10/31/16
to TiddlyWiki
On Monday, October 31, 2016 at 3:45:29 PM UTC-7, Philippe Le Toquin wrote:
What I would ideally like to do is that the text in red (to be discarded) only appears if the return of the macro is YES.
I would like to use the RevealWidget but can't make it works. Here is what I tried
* <$link to={{!!title}}><$view field="title"/> </$link> <$reveal type="match" state="<$macrocall $name="day-left" bestbefore={{!!bestbefore}} />" text="YES">@@color:red;( to be discarded )@@ </$reveal>
but the result of that is not working. Instead it displays:

While the "text" param can contain any desired text, macro call, or transclusion syntax, the "state" param can only be used to specify a TextReference (i.e., a target tiddler field or a DataTiddler property in which to store the current state value).

To use a macro value instead of a stored state value, *omit* the "state" param entirely and use the "default" param instead... something like this:

<$reveal type="match" default=<<day-left bestbefore={{!!bestbefore}}>> text="YES">>

   @@color:red;( to be discarded )@@
</$reveal>

That should do it.  Let me know how it goes.

enjoy,
-e
Eric Shulman
TiddlyTools / ELS Design Studios
InsideTiddlyWiki: The Missing Manuals

BJ

unread,
Nov 1, 2016, 5:49:46 AM11/1/16
to tiddl...@googlegroups.com
HI Philippe,
In addition to what Eric says, I think you need to use a macro like so:

\define stocks (bestbefore)

<$reveal type="match" default=<<day-left $bestbefore$>> text="YES">


@@color:red;( to be discarded )@@
<
/$reveal>
\
end

<$macrocall $name="stocks" bestbefore={{!!bestbefore}} />



All the best

BJ

Philippe Le Toquin

unread,
Nov 1, 2016, 8:34:55 AM11/1/16
to TiddlyWiki
Hi Mark,

I am not sure I understand what you are saying (I am not a real programmer!) so until I understand it, I will try Eric solution.

Philippe

Philippe Le Toquin

unread,
Nov 1, 2016, 8:36:43 AM11/1/16
to TiddlyWiki
HI Eric,

I have tried you method but it is still not working. It is better in the sense that it doesn't print the part I only want to print when it matches but even when it is matching it still stays invisible. The only way to reveal is to set type to nomatch.
 :(

Philippe

Mark S.

unread,
Nov 1, 2016, 11:44:37 AM11/1/16
to TiddlyWiki
Hi Philippe,

Can you share your version of the day-diff.js macro?

I notice that there is a small typographical error in Eric's post. It's the double arrow at the end of the first <$reveal> widget. Perhaps you caught that?

Good luck!
Mark

Philippe Le Toquin

unread,
Nov 1, 2016, 1:20:01 PM11/1/16
to tiddl...@googlegroups.com
Hello

Here is my macro and yes I had noticed the extra >

/*\
title: $:/_ppmt/macros/day-left.js
type: application/javascript
module-type: macro

Takes current day and best before date and return their difference in days

\*/

(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

/*
Information about this macro
*/

exports.name = "day-left";

exports.params = [
	{name: "bestbefore"}
];

/*
Run the macro
*/
exports.run = function(bestbefore) {
	//Make each date object.
        var year= parseInt(bestbefore.substring(0,4));
        var month= parseInt(bestbefore.substring(4,6));
        var day= parseInt(bestbefore.substring(6,8));
	var date1 = new Date(year, month, day);
	var date2 = new Date();

	//Find difference in milliseconds.
	var elapsed = date1.getTime()-date2.getTime();

	//Number of milliseconds in a day.
	var dayMS = 86400000; 

	//Convert milliseconds to year months and days
	var days_diff = Math.floor(elapsed/dayMS);
	
	var result = days_diff;
	if (result>10) { return "NO";}
        else {return "YES";}
};

})();

Mark S.

unread,
Nov 1, 2016, 2:10:00 PM11/1/16
to TiddlyWiki
Hi Philippe,

I've never had any luck passing parameters into a javascript macro the way Eric shows. What's happening, is that the macro is seeing the literal string "{{!!bestbefore}}".

What format are you using for your dates?  Hmm ... looks like you're using the TW format. Not my first choice.

Let me see if I can set your code up the way I use it .... BRB

Mark

Mark S.

unread,
Nov 1, 2016, 2:37:29 PM11/1/16
to TiddlyWiki
This works on my system. Here's how the list is set up:

<$list filter="[!has[draft.of]tag[Stocks]]">
<$set name=bestbefore value={{!!bestbefore}}>
<$link to={{!!title}}><$view field="title"/> </$link> <$reveal type="match" default=<
<day-left>>  text="YES">

   @@color:red;( to be discarded )@@
</$reveal>
<br/>
</$set>
</$list>

This is basically Eric's way, except I'm changing how the variable date gets passed.

Below is  the revised javascript macro. In theory, you should be able to use it with standard parameters (e.g. <<day-left {{!!mydate}}>>) in those cases where you don't need the value used by the calling widget. But you can't use it both ways at the same time, because the version with the parameter takes precedence.

Be sure to make back-ups before testing.

Good luck,
Mark

/*\
title: $:/_ppmt/macros/day-left.js
type: application/javascript
module-type: macro

Takes current day and best before date and return their difference in days

\*/


(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

/*
Information about this macro
*/


exports
.name = "day-left";

exports
.params = [
   
{name: "bestbefore"}
];

/*
Run the macro
*/

exports
.run = function(bestbefore) {


   
var bb = this.getVariable("bestbefore") ;
   
var bestb4 = "" ;
   
   
if(bb) bestb4 = bb ;
   
if(bestbefore) bestb4 = bestbefore ;

   
//Make each date object.
     
       
var year= parseInt(bestb4.substring(0,4));
       
var month= parseInt(bestb4.substring(4,6));
       
var day= parseInt(bestb4.substring(6,8));

Philippe Le Toquin

unread,
Nov 1, 2016, 3:28:25 PM11/1/16
to TiddlyWiki
Brilliant!

Thanks a lot Mark. It now all works. I just had to tweak the macro. The javascript function Date() count month and day from zero!!! so I subsctracted one for each of them in the macro and now it all works.

I still would like to understand why passing parameters the way Eric (and I) are doing is not working :(

thanks a lot for you help.
Philippe
Reply all
Reply to author
Forward
0 new messages