Mixing Magnolia's Vaadin-based AdminCentral and plain javascript

Published on February 21, 2017 by Jan Haderka



Winter is almost over, but in its last attempts to prevail, it's snowing outside right now. What else could you do at this time but try to make it snow on the inside too? And while having fun, also do something useful - namely explain how to mesh custom javascript with the UI of Magnolia AdminCentral.

There's already been one similar presentation on this subject at the 2016 Conference, so it’s not super new, but it never hurts to explain things a few more times.

To get the task done we first need to make snow . Luckily, the Internet is full of scripts making your screen snow. Out of the bunch I found, I took Scott Schiller’s one called Snow Storm purely at random.

The next thing we need is a simple Magnolia module. You can create one by simply running the command below and answering a few questions.

mvn archetype:generate -DarchetypeCatalog=https://nexus.magnolia-cms.com/content/groups/public/

Beware that if you have the latest maven and the latest version of archetype plugin (3.0.0) you might run into this issue.

Anyway, once we have our module created, we can simply delete all the sample code it produced, since we won't need it. Absolutely everything, even the module version handler. What we do need however, is to create a wrapper for our java script. Here it is:


package info.magnolia.snow;

import com.vaadin.annotations.JavaScript;
import com.vaadin.server.AbstractJavaScriptExtension;
import com.vaadin.ui.UI;

/**
 * Storm js wrapper.
 */
@JavaScript({
    "snowstorm.js", "snowstorm_connector.js"
})
public class Storm extends AbstractJavaScriptExtension {

    public static Storm snow(final UI ui) {
        final Storm storm = new Storm();
        storm.extend(ui);
        return storm;
    }
}

You might notice, that apart from the snowstorm.js javascript file that I got off the net, I’m referencing also something called snowstorm_connector.js. More on this file later.

We have a wrapper, so now we need one component. Let’s call it, for lack of a better name and more imagination, a SnowStarter.

import info.magnolia.event.EventBus;
import info.magnolia.ui.api.app.AppLifecycleEvent;
import info.magnolia.ui.api.app.AppLifecycleEventHandler;
import info.magnolia.ui.api.event.AdmincentralEventBus;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import com.vaadin.ui.UI;

/**
 * SnowStorm starter component.
 */
@Singleton
public class SnowStarter {

    @Inject
    public SnowStarter(@Named(AdmincentralEventBus.NAME) EventBus eventBus) {
        final Storm snow = Storm.snow(UI.getCurrent());
    }
}

As you can see, it’s rather simplistic. All it does is attach the JS wrapper of the snowstorm to the current UI like a leach.

Now that we have the component, we also need to tell Magnolia to load our component so that it can attach storm to the UI. This is done via module descriptor

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module SYSTEM "module.dtd" >
<module>
  <name>snow</name>
  <displayName>${project.name}</displayName>
  <description>${project.description}</description>
  <version>${project.version}</version>

  <components>
    <id>admincentral</id>
    <component>
      <type>info.magnolia.snow.SnowStarter</type>
      <implementation>info.magnolia.snow.SnowStarter</implementation>
    </component>
  </components>
  <dependencies>
    <dependency>
      <name>ui-framework</name>
      <version>5.5/*</version>
    </dependency>
  </dependencies>
</module>

 

All right, now Magnolia knows to load our component as part of admincentral. Component will use JS wrapper to attach JS to the UI. The job is almost done. What's left? It’s time for our connector. While the script is set to autostart by default, it is also listening for the event (to start upon) that will not arrive … at least not when script is loaded. So instead, we use our snowstorm_connector.js to kickstart it:

info_magnolia_snow_Storm = function () {
    snowStorm.start();
};

It's as easy as that. Now we have everything, and if we place it at all the correct locations we are ready to start. Yes, right, locations of the files matter. Our java code lies in info.magnolia.snow package, so our javascript files need to exist in folder structure /info/magnolia/snow (where / is top of the jar, so /src/main/resources folder in maven module structure). You can also notice that the name of the function in the connector has to match the package path to the snowstorm javascript wrapper with all the dots (.) in package replaced by underscores (_). 

But with the above, that's really it. Just save all, build & package, copy jar into your Magnolia instance, restart and upon installation, enjoy snowstorm in your instance.

Or just get the whole project from here, build and deploy and …

Or just watch the video if that sounds like too much work.

Admittedly, this extra add-on is not too useful, more annoying, but I hope it serves as a simple guide to how to plug custom javascript in Magnolia AdminCentral. What you do with said JS then is up to you. In case you decide to do something more advanced, know that you can invoke extra functions in your JS file when Magnolia does certain things. E.g if I wanted to call function to change the direction of the snowflakes falling upon opening the app, I could simply add the following in my wrapper:

    public void randomizeWind() {
        getRpcProxy(StormRpc.class).randomizeWind();
    }

 

and bind it via component to event bus to be called upon opening an app:

        eventBus.addHandler(AppLifecycleEvent.class, new AppLifecycleEventHandler.Adapter() {
            @Override
            public void onAppStarted(AppLifecycleEvent event) {
                snow.randomizeWind();
            }
        });

 

I would also need an additional RPC proxy object to relay calls to JS functions:

package info.magnolia.snow;

import com.vaadin.shared.communication.ClientRpc;


/**
 * RPC stub.
 */
public interface StormRpc extends ClientRpc {
    void randomizeWind();
}

 

The function with matching name - randomizeWind() must exist in the snowstorm.js file for this to work.

And that’s really it. You should be all set for experimenting and adding more bells and whistles to your own Magnolia AdminCentral and hopefully inventing something more useful for daily work than what I came up with.

Enjoy.



Comments



{{item.userId}}   {{item.timestamp | timestampToDate}}

About the author Jan Haderka

Jan is Magnolia's Chief Technology Officer. He has been developing software since 1995. On this blog, he'll write about Magnolia's connectors, integrations and coding ...with the odd Magnolia usability and development tip thrown in for good measure. He lives in the Czech Republic with his wife and three children. Follow him on Twitter @rah003.


See all posts on Jan Haderka

Demo site Contact us Free trial