Math.js Plugin

658 views
Skip to first unread message

Matthew Lauber

unread,
Nov 13, 2015, 3:00:11 PM11/13/15
to tiddl...@googlegroups.com
Hey all,

I've wrapped math.js's eval function as a javascript macro.  http://mklauber.github.io/tiddly-mathjs/  For those of you not familiar with math.js and eval, the short of it is that eval is able to intelligently evaluate mathematical expressions while not exposing th typical security issues inherent in eval.  

In addition to just being able to evaluate standard expressions, I've added support for TextReferences among the code, so now you can store data in fields or data tiddlers and right expressions based on that data.  However, one issue I've run into with this is listening for and responding to changes on other tiddlers.  If anyone has a quick suggestion on how to handle that, I would be appreciative.  

Matt Lauber

Matthew Lauber

unread,
Nov 14, 2015, 9:45:23 AM11/14/15
to TiddlyWiki
All, just wanted to let you know I've rewritten the macro as a widget, which means it now responds to widget messages and auto updates.  In addition, this means you can use all the other widgets as part of the body of the calculation.  Want to calculate the sum of the 'stock' field on every tiddler tagged an 'item'?  Pretty straightforward.

<$calc>
<$list filter="[tag[Item]]">
{{!!stock}} +
</$list>
0
</$calc>


On Friday, November 13, 2015 at 3:00:11 PM UTC-5, Matthew Lauber wrote:
Hey all,

I've wrapped math.js's eval function as a javascript macro.  http://www.mklauber.com/mathjs.html  For those of you not familiar with math.js and eval, the short of it is that eval is able to intelligently evaluate mathematical expressions while not exposing th typical security issues inherent in eval.  

ih...@newsfromgod.com

unread,
Nov 14, 2015, 9:55:48 AM11/14/15
to tiddl...@googlegroups.com
Hi Matthew,

> All, just wanted to let you know I've rewritten the macro as a widget,
> which means it now responds to widget messages and auto updates. In
> addition, this means you can use all the other widgets as part of the body
> of the calculation. Want to calculate the sum of the 'stock' field on
> every tiddler tagged an 'item'? Pretty straightforward.
>
> <$calc>
> <$list filter="[tag[Item]]">
> {{!!stock}} +
> </$list>
>
> </$calc>

That is a great plugin, very useful. Thanks for sharing it!

ihm

Jeremy Ruston

unread,
Nov 14, 2015, 11:19:28 AM11/14/15
to tiddl...@googlegroups.com
Hi Matt

Congratulations, that's a terrific piece of work. It's small but leverages both Math.js and TiddlyWiki's architecture to great effect, filling a big hole in TiddlyWiki's current functionality at the same time,

Best wishes

Jeremy

Sent from my iPad

On 13 Nov 2015, at 20:00, Matthew Lauber <ma...@mklauber.com> wrote:

Hey all,

I've wrapped math.js's eval function as a javascript macro.  http://www.mklauber.com/mathjs.html  For those of you not familiar with math.js and eval, the short of it is that eval is able to intelligently evaluate mathematical expressions while not exposing th typical security issues inherent in eval.  

In addition to just being able to evaluate standard expressions, I've added support for TextReferences among the code, so now you can store data in fields or data tiddlers and right expressions based on that data.  However, one issue I've run into with this is listening for and responding to changes on other tiddlers.  If anyone has a quick suggestion on how to handle that, I would be appreciative.  

Matt Lauber

--
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/f7b4055e-fb25-4556-8cee-fc8dc834d8d5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tobias Beer

unread,
Nov 14, 2015, 12:17:22 PM11/14/15
to tiddl...@googlegroups.com
Hi Matthew,

Cools stuff! Wanted to do this for a while, not having picked it up again. :-)

I'd encourage you to ship it as both a macro as well as a widget. Why?

Because you can work with macros as widget attributes and variables. You can't do that with widget output. Clearly, we want to possibly be able to do something with calculated output other than just display it.

If you do create a macro, do not shy from calling it calc. While there is a macro by that name on my end, I'd encourage people to use your version, not both ...as yours is obviously a much more versatile solution than my little bit of code... and if you rely on doing math in TiddlyWiki, that's some  well invested 100k for math.js.

Best wishes,

— tb

Matthew Lauber

unread,
Nov 14, 2015, 1:49:26 PM11/14/15
to TiddlyWiki
My reason for reinventing this as a widget instead of as a macro was that macros don't respond to changes in the virtual Dom, nor can they listen for toddler changed events. This means if you reference a field on another tiddler, you won't update if that value changes.

BJ

unread,
Nov 14, 2015, 2:21:23 PM11/14/15
to TiddlyWiki
very impressive!

BJ

Tobias Beer

unread,
Nov 14, 2015, 6:03:24 PM11/14/15
to TiddlyWiki
Hi Matthew,
 
My reason for reinventing this as a widget instead of as a macro was that macros don't respond to changes in the virtual Dom, nor can they listen for toddler changed events.  This means if you reference a field on another tiddler, you won't update if that value changes.

That problem may actually be trivial to solve.
Simply wrap your macro in a tiddler widget:

<$tiddler tiddler="some tiddler">
<
<calc foo>>
</$tiddler>


Best wishes,

— tb

Matthew Lauber

unread,
Nov 14, 2015, 6:19:56 PM11/14/15
to TiddlyWiki
I can certainly include the marco with limitations.  But the issue is worse than you think, I feel.  For each separate TextReference in the text of the macro, you would need an additional <$tiddler>  block.  

Tobias Beer

unread,
Nov 14, 2015, 6:21:53 PM11/14/15
to TiddlyWiki
Hi Matthew,
 
I can certainly include the marco with limitations.  But the issue is worse than you think, I feel.  For each separate TextReference in the text of the macro, you would need an additional <$tiddler>  block.

Well, that won't work, obviously.

@Jeremy, any remedy / strategy in sight?

Best wishes,

— tb

Matthew Lauber

unread,
Nov 14, 2015, 6:23:40 PM11/14/15
to tiddl...@googlegroups.com
I've released an updated version of this that handles expressions that cannot be parsed.  previously, it would raise an uncaught script error, resulting in a big red "It crashed!" issue.  Now it replaces the text with the phrase "Unable to parse '{{expression}}'".

Matt Lauber

Tobias Beer

unread,
Nov 14, 2015, 6:35:25 PM11/14/15
to tiddl...@googlegroups.com
Hi Matthew,

How about:

<$calc id="result" display:"none">{{Text!!Reference}} / 2</$calc>

<<= result>>
<<= result int>>
<
<= result float>>

?

Whereas...
  • int => parses innerHTML as integer
  • float => parses innerHTML as float 
...and returns the value as a string, obviously.

Best wishes,

— tb

Matthew Lauber

unread,
Nov 14, 2015, 6:39:50 PM11/14/15
to TiddlyWiki
Oohh... I think making the widget export it as a variable would be pretty easy and super useful, and then making those other macros would be simple.  Thanks, this is why I love feedback, doubt I ever would have thought of that.  I'll try to get that up in the next couple days.  


On Saturday, November 14, 2015 at 6:35:25 PM UTC-5, Tobias Beer wrote:
Hi Matthew,

How about:

<$calc id="result" display:"none">{{Text!!Reference}} / 2</$calc>

<<int result>>
<
<float result>>
<
<string result>>
<
<bool result>>

?

Whereas...
    • int => parses innerHTML as integer
    • float => parses innerHTML as float 
    • string => fetches innerHTML as string
    • bool =>  parses innerHTML as boolean
    ... and returns the value as a string, obviously.

    Best wishes,

    — tb

    Tobias Beer

    unread,
    Nov 14, 2015, 6:51:19 PM11/14/15
    to TiddlyWiki
    Hi again, Matthew,

    I've updated the macros above once more,
    before closing those eyelids for tonight ;-)

    Turns out, I like this more:

    <<= some-reference>>

    Best wishes,

    — tb

    Tobias Beer

    unread,
    Nov 14, 2015, 7:01:57 PM11/14/15
    to TiddlyWiki
    Ok, damn it, sleep deprivation :D

    So, final proposal for today:

    <$hide id="some-reference"><$calc>1 + 1</$calc></$hide>
    <<= #some-reference>>

    even...

    <$hide class="some-reference"><$calc>1 + 1</$calc></$hide>
    <$hide class="some-reference">1</$hide>
    <<= .some-reference>>

    ...returning "2 1", so you can retrieve and thus also concatenate ANY widget contents, not just from a CalcWidget.

    Best wishes,

    — tb

    Tobias Beer

    unread,
    Nov 15, 2015, 1:34:02 AM11/15/15
    to tiddl...@googlegroups.com
    At 2nd thought, there's no need for another widget:
     
    <p id="some-reference" class="tc-hide"><$calc>1 + 1.1</$calc></p>
    <<= #some-reference int>>

    returns: 
    2

    or...

    <p class="some-reference tc-hide"><$calc>1 + 1</$calc></p>
    <p class="some-reference tc-hide">1.1</p>
    <<= .some-reference float>>

    returns: 2 1.1

    Best wishes,

    — tb

    Matthew Lauber

    unread,
    Nov 15, 2015, 6:48:43 AM11/15/15
    to TiddlyWiki
    This is more what I was picturing.

    <$calc variable="some-variable">1 + 1</$calc>
    << some-variable >>

    or

    <$calc variable="some-variable">1 + 1</$calc>
    <<= some-variable int >>
    <<= some-variable float >>

    Where adding the "variable" parameter means the <$calc> block doesn't add anything to the DOM at all.  No need for a second block to hide it.  Just stores it in a variable the same as any other widget.   Then we can look at if casts make sense or not.  Honestly, I feel like that should be part of the expression, not the macro.  

    BJ

    unread,
    Nov 15, 2015, 7:39:38 AM11/15/15
    to tiddl...@googlegroups.com
    Hi Matt,
    I think variables have to be used like this;

    <$set name="myVariable" value="Some text">
    <$text text=<<myVariable>>/>
    </$set>
    i.e.

    the setting (writer) widget needs to  be the parent of the reading widgets.

    so you could do:

    <$calc variable="some-variable">
    1 + 1
    <$results>
    << some-variable >>
    <$/results>
    </$calc>

    all the best
    BJ

    Tobias Beer

    unread,
    Nov 15, 2015, 8:22:30 AM11/15/15
    to tiddl...@googlegroups.com
    Hi Matabele,
     
    I think variables have to be used like this;

    I think the point is to follow a different paradigm than variables / macros, because those follow the "attribute-evaluation" paradigm whereas the proposal takes the output of any given dom-/widget-tree rendered before and then reads that into a variable. Quite straight forward, it seems, and also quite independent from any nesting requirements... which feels rather appealing, following an entirely new pattern.

    However, the problem with an example like...

    <p class="my-var tc-hide"><$calc>{{Text!!Reference}} + {{Another##reference}}</$calc></p>
    <<= my-var>>

    ...would still be: How does the instance / value of <<= my-var>> get updated should the values retrieved from the above text-references change?

    It's pretty much the very same problem that Matthew pointed out to begin with, that the macro would never get updated should the references it relies on update, in this case form a widget(-tree).

    So, what appears necessary and hopefully possible is that a calc macro would...
    1. parse its expression for text references
    2. register a change handler for any of those references at the respective parent widget / element where it is used as an attribute
      • this would trigger an update to the widget-tree should any references change
    3. if used as-is in wikitext, that is: not as an element attribute, it would output a <$calc> widget which then does all the update handling
    @Matthew, @Matabele, @Jeremy: Does that make sense?

    Best wishes,

    — tb

    Erwan

    unread,
    Nov 15, 2015, 1:38:44 PM11/15/15
    to tiddl...@googlegroups.com

    Hi Matt,

    can I add your wiki to the list of indexed wikis for the CommunitySearch aggregator please?

    Regards,
    Erwan



    On 13/11/15 20:00, Matthew Lauber wrote:
    Hey all,

    I've wrapped math.js's eval function as a javascript macro.  http://www.mklauber.com/mathjs.html  For those of you not familiar with math.js and eval, the short of it is that eval is able to intelligently evaluate mathematical expressions while not exposing th typical security issues inherent in eval.  

    In addition to just being able to evaluate standard expressions, I've added support for TextReferences among the code, so now you can store data in fields or data tiddlers and right expressions based on that data.  However, one issue I've run into with this is listening for and responding to changes on other tiddlers.  If anyone has a quick suggestion on how to handle that, I would be appreciative.  

    Matt Lauber

    Matthew Lauber

    unread,
    Nov 15, 2015, 2:34:24 PM11/15/15
    to TiddlyWiki
    @Erwan, I don't have a problem with it, but give me a day or two?  I'm working on moving this to a github.io site, and I'm not sure what the exact final address will be.

    Matthew Lauber

    unread,
    Nov 15, 2015, 3:23:35 PM11/15/15
    to TiddlyWiki
    You can use http://mklauber.github.io/tiddly-mathjs/latest.html  I'm going to try to get my build process to keep and document old versions of my plugin, but that link will always have the latest version of the plugin.

    Erwan

    unread,
    Nov 15, 2015, 6:49:20 PM11/15/15
    to tiddl...@googlegroups.com

    Perfect, thanks!
    Anyway I can always update the address later if needed. Normally if you post it on the group I should be able to see it (normally...)

    Erwan

    Matthew Lauber

    unread,
    Nov 15, 2015, 11:32:26 PM11/15/15
    to tiddl...@googlegroups.com
    All, the official source for this plugin now lives at https://github.com/mklauber/tiddly-mathjs  Feel free to fork and/or open PRs for improvements.  The latest version of it will be available automatically at http://mklauber.github.io/tiddly-mathjs/latest.html and older versions at http://mklauber.github.io/tiddly-mathjs/x.x.x.html 

    Matthew Lauber

    unread,
    Nov 16, 2015, 7:15:52 PM11/16/15
    to TiddlyWiki
    One quick update.  I've released version 1.1.0 which includes a new parameter "silence" which silences the parse error text.  This is for use with forms where having the parse error text visible while changing the input in not desired.  Still available at http://mklauber.github.io/tiddly-mathjs/  You can get the older version at http://mklauber.github.io/tiddly-mathjs/1.0.0.html

    Tobias Beer

    unread,
    Nov 17, 2015, 9:06:13 AM11/17/15
    to tiddl...@googlegroups.com
    Hi Matthew,

    This is more what I was picturing. 
     
    <$calc variable="some-variable">1 + 1</$calc>
    << some-variable >>

    I'd have to agree with BJ here that using the term "variable" this way is confusing, if not wrong, at least inconsistent with how that term is already reserved for something else in TiddlyWiki.

    So, if we'd go with any the hidden-widget + macro construct, it would have to be via referencing an element in the widget-tree via either some id or some class as indicated above... which makes me think that actually all widgets should, by default, provide a capability to specify at least an id attribute.

    However, yay (!), it appears that the next version for TiddlyWiki will actually refresh thusly enabled widgets should certain of its computed attributes change! ...provided the widget using a calc macro was set up that way, e.g. to watch for changes to a given attribute.

    So, this will work, if properly resolved:

    <p id="some-reference" class="tc-hide"><$calc>1 + 1.1</$calc></p>

    <$some-widget attr=<<= #some-reference int>>/>

    In other words, if some-widget was implemented such that it will watch for changes to attr and refresh, then we're good to go.

    Now, a perhaps better method compared to retrieving the inner text of any id-referenced chunk in the widget tree would be to specify a math expression so that it can be used as a widget attribute.

    The following looks like it should work:

    <$vars bar=<<calc "{text!!reference} - <baz>">> frotz=<<calc "{!!gronk}^3/4">>>
    <$some-widget foo=<
    <bar>> mumble=<<frotz>>/>
    </$vars>

    This way, when used as a macro parameter, a text reference or macro needs to be specified for use in the calc macro's expression parameter the very same way they are specified in a filter expression, so as to circumvent any requirements that would necessitate using the MacroCallWidget.

    Best wishes,

    — tb

    Xavier Cazin

    unread,
    Nov 17, 2015, 10:25:05 AM11/17/15
    to tiddl...@googlegroups.com
    Hi Matthew,

    Thank you for this very useful plugin. I run into a strange effect, though: when I try to use it on a list (say, in a mylist field), the following code gives its result around brackets:
    <$calc>
    <$list filter="[list[!!mylist]]">
    <$view field="title"/> +
    </$list>
    0
    </$calc>

    Can you figure why?

    Best,
    Xavier.

    -- Xavier Cazin

    On Tue, Nov 17, 2015 at 1:15 AM, Matthew Lauber <ma...@mklauber.com> wrote:
    One quick update.  I've released version 1.1.0 which includes a new parameter "silence" which silences the parse error text.  This is for use with forms where having the parse error text visible while changing the input in not desired.  Still available at http://mklauber.github.io/tiddly-mathjs/  You can get the older version at http://mklauber.github.io/tiddly-mathjs/1.0.0.html

    --
    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.

    Matthew Lauber

    unread,
    Nov 17, 2015, 10:53:10 AM11/17/15
    to TiddlyWiki
    Xavier,
       As far as I can tell, I think it has to do with the basics of math.js It doesn't know whether "0 +1" means "0 + 1" or a list of two items "0" and "+1".  You can resolve it by wrapping the entire expression in parens.  

    <$calc>(

    <$list filter="[list[!!mylist]]">
    <$view field="title"/> +
    </$list>
    0
    )</$calc>

    Xavier Cazin

    unread,
    Nov 17, 2015, 11:51:25 AM11/17/15
    to tiddl...@googlegroups.com
    Hi Mattew,

    No change. The computation does happen with or without parenthesis, but the brackets remain. Here is a modifid Examples tiddler in attachment.

    Xavier.

    -- Xavier Cazin

    Examples.json
    Examples(1).tid

    Matthew Lauber

    unread,
    Nov 17, 2015, 1:46:39 PM11/17/15
    to TiddlyWiki
    Huh.  Not sure what's going on there.  I'll have to dig into it.  (I'm using basically the exact same code in one of my own projects.) I've opened an issue here https://github.com/mklauber/tiddly-mathjs/issues/1

    Matthew Lauber

    unread,
    Nov 18, 2015, 8:04:04 AM11/18/15
    to TiddlyWiki
    Hi Xavier,
    Tobias tracked down the cause of this as the trailing newline after the last number in the list.  I've released a new version of the plugin http://mklauber.github.io/tiddly-mathjs/1.1.1.html that will trim the input to resolve issues like these.  

    Matt Lauber


    On Tuesday, November 17, 2015 at 10:25:05 AM UTC-5, Xavier wrote:

    Xavier Cazin

    unread,
    Nov 18, 2015, 8:46:36 AM11/18/15
    to tiddl...@googlegroups.com
    Wonderful. This new version works like a charm. Being able to process list fields opens another range of possiblities.

    Cheers,
    Xavier.

    -- Xavier Cazin

    Charlie Veniot

    unread,
    Sep 18, 2020, 8:53:10 PM9/18/20
    to TiddlyWiki
    Hey Matt,

    I just found your plugin a couple of days ago, and I wanted to give you a thank-you for that good stuff.  It solved a headache I've been having for the better part of a week.

    If anybody wants to check out how I am using the plugin, take a peek at my Product Reviews / Urban Off Gridding for Laypersons dual-persona TiddlyWiki.

    A few teaser screenshots below.

    Cheers !

    Shot1.png


    Shot2.png


    Shot3.png




    On Friday, November 13, 2015 at 4:00:11 PM UTC-4, Matthew Lauber wrote:
    Hey all,

    I've wrapped math.js's eval function as a javascript macro.  http://mklauber.github.io/tiddly-mathjs/  For those of you not familiar with math.js and eval, the short of it is that eval is able to intelligently evaluate mathematical expressions while not exposing th typical security issues inherent in eval.  
    Reply all
    Reply to author
    Forward
    0 new messages