Running
Action Invoker actions from a
web view displayed by CSPro requires using JavaScript to call into the Action Invoker with the proper permissions granted using
access tokens.
Unlike when using
embedded JavaScript, the Action Invoker is not automatically added to the
DOM. To access this functionality, add the following script tag:
<script src="/action-invoker.js"></script>
The local web server that is run when a web view is displayed will properly find this script file, which is located in the
html directory.
To use the Action Invoker, you must first create an instance of the
class CSProActionInvoker, which is defined in
action-invoker.js. You can name the object anything, but in the help documentation, the object is named
CS to match how the Action Invoker is used in
CSPro logic and
embedded JavaScript:
const CS = new CSProActionInvoker();
Each Action Invoker namespace is an object of CSProActionInvoker, with its actions available as methods in two forms:
- Synchronous (sequentially): Use the action name.
- Asynchronous (concurrently): Use the action name followed by Async. These methods return a Promise to run the action. Asynchronous actions are run in a separate thread from the web view.
If applicable, an action's arguments are specified by passing an object to the method with the arguments defined by using the action's argument names as the object's properties. For example, the following code puts the text "CSPro" onto the clipboard:
CS.Clipboard.putText({
text: "CSPro"
});
When calling actions asynchronously, you can use standard Promise handling, including
chaining. This example shows how to use
alert to display the text contents of a file selected by the operator:
CS.Path.selectFileAsync({
title: "Select a Text File",
filter: "*.txt"
})
.then(selectedPath => {
if( selectedPath === undefined ) {
throw new Error("You must select a file.");
}
return CS.File.readTextAsync({
path: selectedPath
});
})
.then(fileText => {
alert("The file contents are:\n\n" + fileText);
})
.catch(error => {
alert(error);
});
Arguments to actions are specified in one of the
JSON types: string, number, boolean, array, or object. The help page for each action will list the type, or types, permitted for each argument.
On successful execution, the result of an action is returned as undefined, or one of the JSON types: string, number, boolean, array, or object. On error, an exception is thrown.
At runtime, if any of the arguments are invalid, or if there was an error executing the action, the Action Invoker throws an
exception. Each action's help page will indicate if the action throws exceptions. If so, you will want to wrap the action call in
try/catch, or add a
catch method when calling the action asynchronously.
Because content shown in web views may not necessarily come from trusted sources,
access tokens are used to control access to the Action Invoker. When using JavaScript from
untrusted web views, there are two ways to specify an access token. You can instantiate the
CSProActionInvoker class by passing the access token as an argument to the constructor:
const CS = new CSProActionInvoker("the-access-token");
Alternatively, you can set the object's accessToken property prior to executing an action:
CS.accessToken = "the-access-token";
The Action Invoker executes actions sequentially and it is not possible to execute more than one action on different threads from the same web view. This means that if you call an action asynchronously, you cannot call an action synchronously until the asynchronous action has completed. A synchronous call will result in an exception if it cannot run within 200 milliseconds of execution. As a rule of thumb, you will have no issues if you only execute actions synchronously or asynchronously. However, if you execute an action asynchronously, it is a good idea to also execute any subsequent actions asynchronously.
Because of other threading issues with the web view, if an action displays UI elements as part of its operations, you must use the asynchronous, non-blocking, version of the action. If you do not, the action may appear unresponsive or the web view may hang.
The
Chromium-based web view has a different
window object on Windows and Android, so the
CSProActionInvoker class includes a method,
getWindowForEventListener, that gives the proper object for the platform. This can be used as follows:
CS.getWindowForEventListener().addEventListener("message", event => {
// ...
});
Each web view is assigned an ID that uniquely identifies the window. It is available by calling
UI.enumerateWebViews:
const thisWebViewId = CS.UI.enumerateWebViews().webViewId;
When displaying multiple, stacked, web views, you may need this ID when calling actions such as
UI.postWebMessage, which sends a message to the
window object.