Shaun Hevey
Scriptable and Shortcuts
February 10, 2020

Lately I have been playing around with Scriptable and running these scripts from within the Shortcuts application.

If you haven't played around with running your Scriptable scripts in Shortcuts, Scriptable allows you to run scripts in Shortcuts without leaving the Shortcuts application. You can read more about this feature in the docs checkout the args section to find out how you can pass information to your script from shortcuts and the Script section to find out how to pass information from your script to Shortcuts.

Let's create a basic script that can transfer data to and from Shortcuts

For this tutorial I want to create a script that takes some text and formats the text and passes it back to the Shortcut action. Let's start with creating the script and then how you set up a Shortcut to use this script.

Creating the script

Let's start by Creating a new script and calling it ShortcutsTextFormatter

Setting script name

Now add the following functions these are the functions that will actually format the text

const UpperCase = (text) => {
return text.toUpperCase();
};

const LowerCase = (text) => {
return text.toLowerCase();
};

These two functions are pretty simple the both take a simple parameter and the return the parameter with upper cased or lower cased.

Allow Shortcuts to interact with the script

By default any script in Scriptable can be run in the Shortcuts app but if you want to be able to provide data to the script or return data from the script to Shortcuts you will need to add a few more lines of code.

Let's add the following lines to the script.

var actionParam = args.shortcutParameter;

var text = args.plainTexts[0];

if (actionParam == "uppercase") {
Script.setShortcutOutput(text.toUpperCase());
}
else if (actionParam == "lowercase") {
Script.setShortcutOutput(text.toLowerCase());
}

Script.complete();

Let's look at this code block by block.

The following line of code gets the parameter that was passed from the Shortcuts action.

var actionParam = args.shortcutParameter;

This is mapped to this parameter in the Shortcuts action.

Scriptable Shortcut parameter

Scriptable has a number of options for passing data in from Shortcuts to your script the following line is passing text data in. This code will only work on the first item that is passed in.

var text = args.plainTexts[0];

This is mapped to this parameter in the Shortcuts action.

Scriptable Shortcut text input

The next block of code is actually doing the work on the data that is passed in. This code is only handling the two cases of 'uppercase' and 'lowercase' but it isn't handling if any other parameter is passed in it wont be handled.

This block is also setting the output of the script for Shortcuts with the `Script.setShortcutOutput' method.

if (actionParam == "uppercase") {
Script.setShortcutOutput(text.toUpperCase());
}
else if (actionParam == "lowercase") {
Script.setShortcutOutput(text.toLowerCase());
}

This last block of code tells the Shortcuts action that the script has been completed, if you don't add this line of code then Shortcuts has to use heuristics to work out when it has been completed.

Script.complete();

Scriptable Shortcut in action

A few notes about this code it is doing the minimum to actually be able to pass data in and out to Shortcuts but there is a whole lot more you should do. That is where this next module I have created comes in.

ShortcutActions module

This module has been created to make it easy to expose actions from your script to Shortcuts.

To use this module you have to import the module and then you use the AddAction method to expose an action to Shortcuts but more on that later in this post. When you have defined all your actions, you need to call the Run method.

Here is the preceding code example now using this module to expose the same functionality. As you can see it is slightly different to previous example as it will handle multiple parameters passed in.

let sa = importModule('ShortcutActions');

sa.AddAction("Uppercase", "text", function(text) {
var results = [];
text.forEach(function(item, index) {
var data = item.toUpperCase();
results.push(data);
});

return results;
});
sa.AddAction("Lowercase", "text", function(text) {
var results = [];
text.forEach(function(item, index) {
var data = item.toLowerCase();
results.push(data);
});

return results;
});

sa.Run();

Let's take a look at the AddAction method in depth. This method takes three parameters the first is the name of the action that you want to expose. This is the text that needs to be passed in to the script in this parameter.

Scriptable Shortcut parameter

The second parameter is to define the parameters that will be passed in to the method for the action. This can either be an array of identifiers or a single identifier. The following identifiers are available text, url, image, file or null if no parameters are to be passed in. Your function that you have defined for the action must have the same number of parameters as identifiers defined. Note: The order of the identifiers defined will be the order the arguments will be passed in the action function.

Each of the identifier map to the four optional parameters from the Shortcut action see the image below for the mapping.

Scriptable Shortcut text input

The last parameter is the function that will be called by the module if it is called by the Shortcuts action. As defined above the number and order of the parameters must match the identifiers passed in for the second parameter. This method must return the data that you want to be passed back to Shortcuts.

This module also has the ability to expose the list of actions that have been defined to Shortcuts. This will happen if you pass no parameter to the script (this can be turned off by the following line. sa.exposeHelpAsDefault = false) or by passing the following text in as the parameter Script:GetActions.

Let's take a look at what this looks like in Shortcuts.

Scriptable Shortcuts module in action

If you would like to grab a copy of this module then you can find it here or from the embedded gist below.

Once you have saved it in to your Scriptable library then you can import it in to any script to start exposing actions easily.