Backend Live - Javascript Actions
The Javascript Actions extension provides you with the ability to define your own Action that can be used in subapp Action Bars or in Dialogs. You just need to create a Javascript file that specifies the execute function.
Installing to a Bundle
If you have an existing bundle, perhaps obtained by using the Magnolia CLI, you will need to add the modules as defined at Javascript Models 2.0, as well as its dependencies to each webapp’s  /WEB-INF/lib directories:
Using a standard Magnolia Bundle, these directories would be:
- 
apache-tomcat/webapps/magnoliaAuthor/WEB-INF/lib/
- 
apache-tomcat/webapps/magnoliaPublic/WEB-INF/lib/
Installing with Maven
Maven is the easiest way to install the module. Add the following to your bundle:
<dependency>
  <groupId>info.magnolia.backendlive</groupId>
  <artifactId>backend-live-actions</artifactId>
  <version>1.1.0</version>
</dependency>Configuration
Make sure to follow the Configuration for Javascript Models 2.
You should already have exposed the cmsfn Templating function to your Javascript projects, but if not, this is how the configuration should look in the Configuration app:

Exposed Components can be considered "global", meaning that you do not reference them with this, rather just cmsfn. This will also apply to exposedComponents you define for each definition, which we will explain later.
If you’d like a full list of the default exposeedComponents and a description, you can click "Expand for More"
Expand for More
| Component | Description | 
|---|---|
| 
 | Navigate content and create links. | 
| 
 | Get assets and renditions and create links to assets. | 
| 
 | Get sites and themes. | 
| 
 | Get links to images from any workspace. | 
| 
 | Create links to css and js files by given patterns. | 
| 
 | Access REST clients. | 
| 
 | Search pages and content. | 
| 
 | Create site navigation. | 
| 
 | Get categories (tags) and access content by category. | 
You are now ready to start writing your own custom Javascript component.
Usage
This example will create a new Action using Javascript. This action will allow a user to open a completely different application, with the selected node selected in the subapp that you specify. Specifically, we are going to add an action in the Pages App to jump to the JCR Browser with the selected page, and to also do the same from the JCR Browser to the Pages App.
You can simply add the backend-live-actions-lm project from Backend-Live Samples if you want to see it in action. If you want to get a more hands-on experience, you can create a folder named backend-live-actions-lm in your Light Modules directory.
To create your Action with Javascript, simply create your javascript. The best place to maintain your Javascript files is in your Light Module’s backendScripts directory. In this sample, we are creating the file: light-modules/backend-live-actions-lm/backendScripts/actions/openSubApp.js.
The Javascript
Within this file, we need to create a class, define it’s execute function, and instantiate it. This is necessary for GraalVM to access the function. Here is the generic structure:
var OpenSubAppAction = function () {
    this.execute = function () {
        // Do something when Action clicked.
    }
};
new OpenSubAppAction();- 
Line 1: Create the Javascript Class 
- 
Line 2: Declare the executefunction without parameters
- 
Line 6: At the end of the file you must create an instance 
Because this action will depend on several other Java classes, we can simplify our code by relying on an external utility Javascript file using our loadScript helper method.
Here is the utility class that can be used across multiple actions (or other backend extensions):
var Utils = function () {
    var NodeUtil = Java.type("info.magnolia.jcr.util.NodeUtil");
    var NodeTypes = Java.type("info.magnolia.jcr.util.NodeTypes");
    var DefaultLocation = Java.type("info.magnolia.ui.api.location.DefaultLocation");
    var Location = Java.type("info.magnolia.ui.api.location.Location");
    this.createDefaultLocation = function (locationType, appName, subAppId, path) {
        return new DefaultLocation(locationType, appName, subAppId, path);
    }
    this.getLocation = function () {
        return Location;
    }
    this.getNodeUtil = function () {
        return NodeUtil;
    }
    this.getNodeTypes = function () {
        return NodeTypes;
    }
}| Using `Java.type("full.class.path") exposes a class to Javascript, so you can now do things like:  | 
To use this class, you can modify the action class code like this:
loadScript("/backend-live-actions-lm/backendScripts/utils.js");
var OpenSubAppAction = function () {
    var utils = new Utils();
    this.execute = function () {
        // Do something when Action clicked.
    }
};
new OpenSubAppAction();- 
Line 1: Load the utils.jsusing the Resource File Path.
- 
Line 3: Instantiate the Utilsclass.
- 
Line 8: Create a class instance. 
In this example, we want our action to open an app within a specific subapp of a different app (for example, moving from Pages to JCR Browser, and vice versa). We’ll define some properties in our YAML later, but you can see here how those parameters are made available to the OpenSubAppAction action.
loadScript("/backend-live-actions-lm/backendScripts/utils.js");
var OpenSubAppAction = function () {
    var utils = new Utils();
    this.execute = function () {
        var pathToOpen = "/";
        var nodeUtils = utils.getNodeUtil();
        var nodeTypes = utils.getNodeTypes();
        var jcrItem = this.content;
        if (!jcrItem.isNode()) {
            jcrItem = jcrItem.getParent();
        }
        var isContent = nodeUtils.isNodeType(jcrItem, nodeTypes.Content.NAME);
        if (isContent || (this.parameters.containsKey("useContentSubNodes") && this.parameters.get("useContentSubNodes") === true))  {
            pathToOpen = jcrItem.getPath();
        } else {
            pathToOpen = cmsfn.parent(jcrItem, nodeTypes.Content.NAME).getPath();
            this.log.info("Current node is either not content or useContentSubNodes was set to false: ID: {} pathToOpen {}",
                this.content.getItemId().toString(), pathToOpen);
        }
        var location = utils.createDefaultLocation(utils.getLocation().LOCATION_TYPE_APP, this.parameters.get("appName"),
            this.parameters.get("subAppId"), pathToOpen);
        this.log.info("Moving to {} in the {} app.", pathToOpen, this.parameters.get("appName"));
        locationController.goTo(location);
    }
}
new OpenSubAppAction();- 
Line 15: Use of this.parameterscomes from the YAML definition.
- 
Line 18: Use of cmsfncomes from thejavascript-modelsconfiguration
- 
Line 19: Use of this.logis provided by theJavascriptAction
- 
Line 27: Use of locationControlleris defined in the YAML definition
You may have noticed that there are several references using this to access some local item. Several of these items are made available to you, here is a list of object you have access to locally:
| Component | Description | 
|---|---|
| 
 | Custom definition items defined in the YAML file under the  | 
| 
 | This is the item selected when clicking on the Action. If in the Pages App, it is the page node, for example. | 
| 
 | This is the YAML definition that you’ve specified when declaring the  | 
| 
 | This is a shorthand representation of the  | 
| 
 | This is the Magnolia Log4j log bound to the Javascript Action class. You can log  | 
The YAML
The final piece of the puzzle is to put this all together. Here’s what a typical app action definition would look like when you use a custom Java class:
subApps:
  browser:
    actions:
      toJcrBrowserApp:
        $type: openSubAppAction
        appName: jcr-browser-app
        subAppId: browserIn this case, the Action’s Definition class provides two properties appName and subAppId to be available. To make our Javascript class possible, here’s how our definition would look:
subApps:
  browser:
    actions:
      toJcrBrowserAppJs:
        $type: jsAction
        modelPath: /backend-live-actions-lm/backendScripts/actions/openSubApp.js
        parameters:
          appName: jcr-browser-app
          subAppId: browser
        exposedComponents:
          locationController:
            componentClass: info.magnolia.ui.api.location.LocationController
            name: locationController- 
Line 5: All actions are now jsAction
- 
Line 6: modelPathis now what distinguishes its actual execution
- 
Line 7: parametersare free-form and can be reused in the Javascript viathis.parameters.<NAME>
- 
Line 10: exposedComponentscan be made available if not defined in thejavascript-modelsconfiguration
Now if you add it to your actionbar (as you can see in backend-live-actions-lm/decorations/pages-app/apps/pages-app.yaml), the button will be available to the Pages App.
| Property | Description | ||
|---|---|---|---|
| 
 | Required (if not using  The value must be
 | ||
| 
 | Required (if not using  The class must be
 | ||
| 
 | Required
The path to the Javascript class. This is the  | ||
| 
 | This is a free-form set of parameters that you can use within your Javascript class that would look like this:  | ||
| 
 | You can expose Java  
 | ||
|       | The arbitrary name that will be used to access the defined class. | ||
|           | The Java class that will expose its  | ||
|           | The arbitrary name that will be used to access the defined class. | 
Samples
There are light-module samples for each of the projects found in our Backend-Live Samples repository.
Once you check out the project, you can simply copy the light-modules/backend-live-actions-lm folder into your magnolia.resources.dir location (defined in YOUR-WEB-APP/WEB-INF/config/default/magnolia.properties).
If you are interested in a more complex demonstration, and tutorial on how to use multiple extensions in conjunction with each other, you may be interested in checking out our Backend Live Demo project.