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.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
execute
function 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.js
using the Resource File Path. -
Line 3: Instantiate the
Utils
class. -
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.parameters
comes from the YAML definition. -
Line 18: Use of
cmsfn
comes from thejavascript-models
configuration -
Line 19: Use of
this.log
is provided by theJavascriptAction
-
Line 27: Use of
locationController
is 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: browser
In 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:
modelPath
is now what distinguishes its actual execution -
Line 7:
parameters
are free-form and can be reused in the Javascript viathis.parameters.<NAME>
-
Line 10:
exposedComponents
can be made available if not defined in thejavascript-models
configuration
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.