• <GetStart>
  • CSPro User's Guide
    • The CSPro System
    • Data Dictionary Module
    • The CSPro Language
    • Data Entry Module
    • Batch Editing Applications
    • Tabulation Applications
    • Data Sources
    • CSPro Statements and Functions
    • Templated Reporting System
    • HTML and JavaScript Integration
    • Action Invoker
      • Overview
      • Execution Environments
        • CSPro Logic
        • OnActionInvokerResult Global Function
        • JavaScript (Embedded)
        • JavaScript (From Web Views)
        • JSON
        • Android Intent
      • Security and Formatting Options
      • Base Actions
      • Application Namespace
      • Clipboard Namespace
      • Data Namespace
      • Dictionary Namespace
      • File Namespace
      • Hash Namespace
      • Localhost Namespace
      • Logic Namespace
      • Message Namespace
      • Path Namespace
      • Settings Namespace
      • Sqlite Namespace
      • System Namespace
      • UI Namespace
    • Appendix
  • <CSEntry>
  • <CSBatch>
  • <CSTab>
  • <DataViewer>
  • <TextView>
  • <TblView>
  • <CSFreq>
  • <CSDeploy>
  • <CSPack>
  • <CSDiff>
  • <CSConcat>
  • <Excel2CSPro>
  • <CSExport>
  • <CSIndex>
  • <CSReFmt>
  • <CSSort>
  • <ParadataConcat>
  • <ParadataViewer>
  • <CSCode>
  • <CSDocument>
  • <CSView>
  • <CSWeb>

Action Invoker Execution from JavaScript Run from Web Views

Overview
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);
});
Argument Types
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.
Return Values
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.
Exception Handling
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.
Access Tokens
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";
Threading and User Interface Implications
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.
See also: Action Invoker Overview, Action Invoker Access Tokens, Action Invoker Execution from Embedded JavaScript