A somewhat of a documentation of hidden formulas [Added mechanics of nested buttons]

It might be interesting to separate out the formula in simple and advanced formula. The advanced formula can be separated off, but made more stable.
There’s a definite need for some of the more complex formula in Coda, but I can also see the reason as to why these formula are hidden.

1 Like

Dear @Filmos,

What a source of inspiration, “:large_blue_diamond: science fiction :large_blue_diamond:” in Coda :+1:

1 Like

Advanced usage of the Color() formula [Back to index]
Disclaimer: this functionality is very likely to change in the near future.

The Color() formula is implemented in a very interesting way, which allows this formula for more than just changing the font color.
You can use special keywords, combined with spaces, to change the text even more.
For example, you can create red text on a green background by using
_Color('kr-green-light-bg kr-red-dark-fg',"Text")

Unfortunately, this does not work with the hex colors.

List of keywords:

  • kr-[color class]-fg – changes font color
  • kr-[color class]-bg – highlights the text with given color
  • kr-highlight – highlights the text in yellow (#fff59d, color which isn’t achievable with a color class)
  • kr-[color class]-interactive-text – changes font color and makes it react to mouse events
  • kr-[color class]-interactive – highlights the text with given color and makes it react to mouse events
  • kr-bold – makes the text bold
  • kr-italic – makes the text italic
  • kr-underline – adds an underline to the text
  • kr-line-through – adds a strike-through to the text

Nesting
Unlike other text formatting functions, this one doesn’t allow for nesting.
The outer Color() formula will completely overwrite all other Color() formulas.

This means that while

_Bold(_Italicize("Text"))

creates text that is both bold and italic,

_Color('kr-bold',_Color('kr-italic',"Text"))

will create text which is only bold.

This also means that partially overlapping formats like

_Bold("Partially ",_Italicize("Italic"))

have to be split into

Concatenate(
  _Color("kr-bold", "Partially "),
  _Color("kr-bold kr-italic","Italic")
)

[Back to index]

@Filmos hmm you post creates such opposing emotions. I really want to use _bold() … but don’t want to risk destroying my document … and much effort to failsafe it for a bold. Do you think adding _bold() to a formula risks the entire doc?

1 Like

@Johg_Ananda this is actually a really important matter that I failed to add here.

I’d say that the _Bold(), _Italicize(), _Strikethrough(), _Underline(), _Highlight() and _Code() formulas are 99.9% safe.
Since they don’t use any arguments other than text, if there were any drastic changes to them (which is pretty unlikely on its own) either their syntax would stay the same or they would require additional parameters, which would make it nearly impossible for such a formula to crash the document.

Formulas such as _Color(), _RichText(), Identity(), _NoOp() or Activate() are slightly more unstable, but it is still incredibly unlikely that they will cause any major problems with the document.

However, other formulas can be pretty dangerous. For example the Button() formula (which is the one I use the most) can already create a lot of problems with the document. And if you add to this coda updates things can get pretty serious.
Those kind of formulas were the main reason why I had to come up with all those fail-safe procedures.

EDIT
Inspired by this question I grouped hidden formulas based on how likely they are to cause problems.

1 Like

Holy sh~ how did you find that out? Dug deeper into the JS?

1 Like

Yup, I’ve put it through a few beautifiers until I got a semi-readable code.
And each formula is defined as an object with a standard js function for getting the result.

And using the _Merge() formula to view the computed column results as json was the key to reading the obfuscated javascript.

1 Like

Fiddling with your research doc I found out about the $$ operator used to create references.

E.g. $$[cell:grid-ahmvaWqCgY:c-ni32haMaa_:i-pHC2juX1xr:false:false:Value]


Syntax goes [<type>:<tableId>:<columnId>:<rowId>:<bool>:<bool>:<displayName>]. Some params can be omitted depending on type. Not sure what the bools are for either.

Types are (click to see)
"canvas";
"cell";
"column";
"controlGrid";
"document";
"grid";
"row";
"rowColumn";
"variable";
"table";
"constraint";
"linkedColumnFormula";
"image";
"volatileFunction";
"fakeReference";
"documentObjectsReference";
"packReference";
"packConnectionReference"

You can also type $$[] anywhere in a formula to break down all references in it.

Still, haven’t found a practical use for it. Since it’s not a string and it needs to be typed, I guess a first step would be using your ParseJSON method to create the object.

My first idea was to programatically insert/get column values. If we just found a way to list columns (as the API does)… there’s a challenge for you @Filmos.

2 Likes

Dear @Filmos, @Dalmo_Mendonca, @Johg_Ananda and @Paul_Danyliuk

I felt so free to move your posts under “Developers Central” as your input is at a higher level what might confuse other users.
Keep up with your magical inputs :handshake:

2 Likes

@Filmos It might be an idea to have some documentation on these calls. Or have someone from Coda provide the missing details.

1 Like

Mechanics of nested buttons [Back to index]
Since 2019-09-12T22:00:00Z buttons can no longer be nested. There is a petition to bring this feature back, but for now all of the information below is deprecated.

With the Button() formula, you can put a button into a label of another button (which is in a label of another button and so on).
image
This kind of nested buttons have a few useful and interesting properties.

Action execution order
When you click on a nested button, it will firstly execute the action of the button you directly clicked.
Then it will execute the action of its parent, and then a parent of the parent, and so on until it reaches the root.

That means that if you were to click the blue button from the image above, action order would be
blue --> green --> yellow --> white, with white overwriting any colliding actions (like changing value of the same row and column).

There is just one big problem - those actions are asynchronous.
That means that they start executing in this order, but the changes may be applied in a completely different one, based on the complexity of the action.
This is fragile to such an extent that just wrapping a formula with RunActions() or adding an if statement (even if it is just If(true,"","")) will change this order.

That means that this order is only reliable when the actions are nearly identical (for example: ModifyRow() with static target, column and value).

Activating only the top button
Clicking only the top-most button can be useful in many cases and it can actually be achieved.
Because of the execution order, when a button action is executed you can check if any other button was clicked earlier. If it was, it means it was above this one.
To do that, you would need to wait (using _Delay()) until the previous action is executed and check if there were any changes using Modified().

While it is possible to create this for more than 2-deep buttons, the delay would stack up and make the buttons pretty slow and impractical. So I’m only going to explain how to achieve that with 2-deep buttons.

The problem is that we need to make sure the background button detects the top button being clicked, even if it has a slow formula.
To do that we can simply change the formula of the top button to

RunActions(
  ModifyRows(thisRow, [Button detection], "W"),
  <the actual formula>
)

This makes sure that the change will be detectable at the same time after the button is clicked, no matter what the complexity of the formula actually is.

Detecting the button change is also tricky.
Because of how the _Delay() formula works, you have to split the action into two buttons.
The first one (the one you actually click) should look like this:

_Delay([Actual action],300)

And the second one should look like this:

if(Now()-Modified(thisRow.[Button detection])<=Seconds(0.35),"",
<the actual action>)

You may be tempted to set the button detection column to Now() when clicking first button, but not only is that value rounded (and basically useless) it will also create a lot of other problems.

Note that you don’t need to use those exact delays, those are just the ones I found reliable.

One more issue
There is still one small issue with this solution - if you click the bottom button fast enough after clicking the top button, the bottom button won’t be activated.

This can be easily fixed by changing the formula of the bottom button to

if(IsNotBlank(thisRow.[Button detection]) && 
   Now()-Modified(thisRow.[Button detection]) <= Seconds(0.35),
 ModifyRows(thisRow,thisRow.[Button detection],""),
 <the actual action>
)

Sandbox

[Back to index]

1 Like

Is there any chance any Codans could tell us the likelihood that FormatDateTime() (and it’s siblings) will change or be removed? Formatting dates/times on the canvas is ridiculously verbose right now, and these functions make it a lot simpler.

2 Likes

@Ian_Nicholson you would need to ask @mallika about that.

I’m also curious what’s the status of hidden formulas and if it possible that those that are more stable (_Bold(), _Italicize() etc.) will be fully implemented soon.

1 Like

Unfortunately due to recent coda update nested buttons are no longer supported, which significantly limits possibilities of hidden formulas.
This includes making deep modifications nearly useless, as you can no longer hide the on-hover box.

Seems like they patched it straight after your post…

That stuff went all a bit over my head since I wasn’t able to test it… I can certainly see the use for the async case, and that’d be great since the only way to run async actions is to manually click the buttons.

But then when you started adding delays, what are (were) the advantages of it over a simple RunActions?

The main advantage of using nested buttons (at least for me) was the ability to create more complex user interface. So that you can either click the big button for one action, or one of the smaller ones on it for a different one.

Example:
image

Maybe it would help if you separate out the example in a shared document? The example you posted is still quite ambiguous.

1 Like

Actually, since I’m no longer going to work on this project using coda I’m going to share it whole.

And, in case anyone is interested in future development of this project, I’m going to post video entries about it on my youtube channel.

1 Like

Using RegexExtract to implement a GroupBy() function: Group By using Hidden Formula RegexExtract

@Filmos @Dalmo_Mendonca @Paul_Danyliuk Anyone maybe know how to get the current URL (of the section displayed) through formula?

I’m trying to use it for filters so I can filter using the current page as context without having to hardcode it.