Unexpected "Cancel" button behavior
I'm using this piece of code in my Move Tracks script (I've modified it slightly here for demo purposes).
sf.ui.proTools.appActivate();
let selectDestinationTrack = (sf.interaction.displayDialog({
prompt: "Select a destination track and click OK.\n \n(Your tracks will be moved below this track)",
defaultButton: "OK",
buttons: ["Top of Session", "OK", 'Cancel'],
//cancelButton: "Cancel",
})).button;
if (selectDestinationTrack == 'Top of Session') {
alert("You selected Top")
} if (selectDestinationTrack == "OK") {
alert("You selected a destination track")
} if (selectDestinationTrack == 'Cancel') {
alert("I'm quitting Now!")
throw 0;
}
I've noticed that the last if
doesn't execute when the user cancels. It seems that just labeling a button "Cancel" makes it cancel execution even if you don't use the cancelButton: "Cancel"
argument as shown above.
The only way I can get the Cancel button to behave the way I want (alert("I'm quitting Now!")
is to add a trailing space after the word Cancel like so:
buttons: ["Top of Session", "OK", 'Cancel ']
Is this the expected behavior?
- Christian Scheuer @chrscheuer2020-07-11 21:35:56.365Z
Hi Chris,
I think you need to add the property
onCancel: 'Continue'
to thedisplayDialog
call if you want a Cancel click to not stop your script.Christian Scheuer @chrscheuer2020-07-11 21:37:33.511Z
By default SoundFlow (and the user) expects that clicking Cancel on a dialog means the user didn't want to do the thing they started anyway. So that's why the default behavior clicking Cancel is to stop the script (akin to
throw 0
).Christian Scheuer @chrscheuer2020-07-11 21:38:25.174Z
In your case, I don't agree with the logic you're setting up that you should display an alert box after the user has clicked Cancel. That's not typically how clicking Cancel works across normal user interfaces. Normally, clicking Cancel just silently stops the current operation.
Chris Shaw @Chris_Shaw2020-07-11 21:45:38.325Z
I'm just throwing an alert box in the above script as an example piece of code. I probably should have used
log
instead. Sorry for the confusion.Chris Shaw @Chris_Shaw2020-07-11 21:47:34.997Z
When I debug my scripts I use alerts as a way to pause the script and display variables/strings.
Christian Scheuer @chrscheuer2020-07-11 21:50:02.557Z
Makes perfect sense. But I'd still argue in 99% of cases you wouldn't need to handle the behavior yourself after the user has pressed cancel so you could just leave the default behavior as is. Running code after the user has clicked cancel would typically not be what the user expects.
Chris Shaw @Chris_Shaw2020-07-11 21:54:40.106Z
My move tracks scripts creates a show hide memory location to restore the tracks view the user had before executing the script. The the script then displays/unhides all tracks before asking the user for the destination track.
My goal is recall this memory location and then delete it if the user cancels. Hence my need to execute a couple of lines of code before quitting the script.
Christian Scheuer @chrscheuer2020-07-11 21:56:34.150Z
Gotcha :) One of the 1% haha.
I would consider doing this with a try / finally block instead though, as that would also ensure your cleanup code is run in any other exceptional cases (if an error happens during the normal run of events)
Chris Shaw @Chris_Shaw2020-07-11 22:28:04.889Z
hmm, Try / Finally - off to JavaScript school 😄
Christian Scheuer @chrscheuer2020-07-12 11:24:47.678Z
Sorry for the brevity, I was typing most of this on my phone.
The general concept of try/finally is that whatever happens inside the try block, the finally block will ALWAYS be called.
This includes if an exception happens inside the try block, (including a throw 0), and even if you just call return inside the try block - the finally block will ALWAYS be executed.So in your case, instead of trying to overwrite the cancel behavior, I would do:
try { //Call the function here that may or may not cancel out early. //In fact, any code from the moment you do something that needs cleanup until you're done with the whole stuff, should go in your try block } finally { //Do the cleanup here }
Christian Scheuer @chrscheuer2020-07-12 11:26:50.727Z
So for example, in all these cases the alert should show.
try { throw 0; } finally { alert('Cleanup'); } try { //Click cancel and check that Cleanup is still called let selectDestinationTrack = (sf.interaction.displayDialog({ prompt: "Select a destination track and click OK.\n \n(Your tracks will be moved below this track)", defaultButton: "OK", buttons: ["Top of Session", "OK", 'Cancel'], })).button; } finally { alert('Cleanup'); }
Christian Scheuer @chrscheuer2020-07-12 11:27:31.953Z
Note since the finally block is ALWAYS called, this includes of course the regular case where everything goes well inside the try block and no exceptions or return statements are called.
Christian Scheuer @chrscheuer2020-07-12 11:28:28.106Z
Another example where the finally block should be called:
function testFunction() { try { return true; } finally { alert('Cleanup'); } } testFunction();
Christian Scheuer @chrscheuer2020-07-12 11:36:37.011Z
More info on try-catch, try-catch-finally and try-finally blocks here:
https://javascript.info/try-catchChris Shaw @Chris_Shaw2020-07-12 17:49:17.367Z
Thanks for all the info Christian. I read up on this yesterday but seeing it in context of the code I wrote helps immensely…
- In reply tochrscheuer⬆:
Chris Shaw @Chris_Shaw2020-07-11 22:01:49.566Z
I see that
onCancel: 'Continue'
returnsnull
as well.
Good to know
- In reply toChris_Shaw⬆:Chris Shaw @Chris_Shaw2020-07-11 21:37:05.429Z
In other words, It seem that SF or JavaScript automatically binds a stop execution command to any button that is labeled ""Cancel".
Christian Scheuer @chrscheuer2020-07-11 21:48:28.639Z
Correct.
Christian Scheuer @chrscheuer2020-07-11 21:48:46.357Z
Unless you add an onCancel: 'Continue' property as stated previously.
- In reply toChris_Shaw⬆:Chris Shaw @Chris_Shaw2020-07-11 21:48:06.002Z
Thanks for clarifying Christian!