Skip to content
Jakob Voß edited this page Mar 1, 2023 · 10 revisions

Besides changing Skosmos configuration, and modifying the code directly, another option to extend and customize Skosmos is through plugins written in JavaScript.

Creating Plugins

A plugin consists of a folder, with a unique name. The folder name is also used as the plugin name. Within the folder, there should be a file plugin.json, which provides information about each plugin's resources. For example:

{
    "js": ["widget.js"],
    "css": ["stylesheet.css", "anotherfile.css"],
    "templates": ["template.html", "anothertemplate.html"],
    "callback": ["my_callback"]
}

The js resources are used in the Skosmos template file. These JavaScript files are loaded for every page, and are located near the bottom of the page (i.e. near the </body> HTML end tag).

The css resources are loaded also for each page by Skosmos template file. The CSS stylesheet files are put within the HTML <head> section.

The templates resources are loaded for JavaScript, using Handlebars, and the syntax looks like:

<script id="{{ id }}" type="text/x-handlebars-template">
{{ template|raw }}
</script>

The template ID is automatically generated, based on the plugin name, and on the template file name minus the extension. If your plugin name is "acrobata" and the template file name is "privacy.html", the template ID will be "acrobata-privacy".

This is important when you need to use the template in JavaScript. It is also important to note that the extension is extracted simply by creating a substring of the template file name from the position 0 until the first appearance of the . symbol. So if your template file name contains multiple . characters, you may have unwanted template ID's.

The callbacks resources are a called for each page loaded.

Installing Plugins

When you install Skosmos, there should be a folder in the root application folder, called "plugins". Inside this folder you can put your plugin folders. As explained in the previous section, the folder names are used as plugin names as well.

For each request, Skosmos loads the content of each enabled plugins' plugin.json, and utilises its resources, as explained in the previous section.

Plugins are enabled in the configuration file, config.ttl. There are two ways to activate plugins. This is explained in the next section.

Activating Plugins

Global Plugins

The first way to activate plugins in Skosmos is globally. This is done via the skosmos:globalPlugins property in the config.ttl configuration file.

:config a skosmos:Configuration ;
  # ...
  skosmos:globalPlugins ( "plugin1" "plugin2" "plugin3" ) .

This will initialize the plugins "plugin1", "plugin2", and "plugin3" for all Skosmos.

Vocabulary-specific Plugins

The second way to activate plugins, is per vocabulary. This is done via the skosmos:usePlugin property. This property is not from skosmos:Configuration, but added to each skosmos:Vocabulary, zero or multiple times.

:ysa a skosmos:Vocabulary, void:Dataset ;
    dc:title "YSA - Yleinen suomalainen asiasanasto"@fi,
        "YSA - Allmän tesaurus på finska"@sv,
        "YSA - General Finnish thesaurus"@en ;
    # ...
    void:sparqlEndpoint <http://api.dev.finto.fi/sparql> ;
    skosmos:usePlugin "plugin1" ;
    skosmos:usePlugin "plugin2" ;
    skosmos:sparqlGraph <http://www.yso.fi/onto/ysa/>
.

In the example we have the vocabulary ysa, being configured in Skosmos to load the plugins plugin1 and plugin2. These plugins will appear only on the pages of the vocabularies where they were enabled via the skosmos:usePlugin.

Parameterized Plugins

The third way to activate plugins is to use the skosmos:useParamPlugin property. This can be added to a vocabulary multiple times if needed, which then activates those plugins for the vocabulary and it's concept pages.

:ysa a skosmos:Vocabulary, void:Dataset ;
    dc:title "YSA - Yleinen suomalainen asiasanasto"@fi,
        "YSA - Allmän tesaurus på finska"@sv,
        "YSA - General Finnish thesaurus"@en ;
    # ...
    void:sparqlEndpoint <http://api.dev.finto.fi/sparql> ;
    skosmos:useParamPlugin :messageWidget ;
    skosmos:sparqlGraph <http://www.yso.fi/onto/ysa/>
.

:messageWidget  a skosmos:ParameterizedPlugin ;
                skosmos:usePlugin "awesome-message-widget";
                skosmos:parameters [
                        a schema:PropertyValue ;
                        schema:propertyID "msg";
                        Schema:value "Message in Finnish"@fi, "Message in Swedish"@sv, “Default message without language code”;
                    ] ,
                    [
                        a schema:PropertyValue ;
                        schema:propertyID "color" ;
                        schema:value "#800000" ;
                    ] ,
                    [
                        a schema:PropertyValue ;
                        schema:propertyID "imageUrl" ;
                        schema:value "http://example.com/media/unicorn.png" ;
                    ] .

This way it is possible to pass parameters to a plugin. The plugin is identified by skosmos:usePlugin determined for the :messageWidget resource. Each parameter is identified by schema:propertyID. It is up to the plugin to interperet these parameters. An example of this can be seen here.

Plugin order

The fourth way to activate plugins is skosmos:vocabularyPlugins property. skosmos:vocabularyPlugins can have a list of names of global and vocabulary specific plugins or references to plugin resources e. g. parameterized plugins. skosmos:vocabularyPlugins orders the execution and rendering of vocabulary-specific and global plugins.

:ysa a skosmos:Vocabulary, void:Dataset ;
    dc:title "YSA - Yleinen suomalainen asiasanasto"@fi,
        "YSA - Allmän tesaurus på finska"@sv,
        "YSA - General Finnish thesaurus"@en ;
    # ...
    void:sparqlEndpoint <http://api.dev.finto.fi/sparql> ;
    skosmos:vocabularyPlugins ( "plugin2" :messageWidget "plugin1" ) ;
    skosmos:sparqlGraph <http://www.yso.fi/onto/ysa/>

:messageWidget  a skosmos:ParameterizedPlugin ;

If a vocabulary-specific plugin name or resource is listed in skosmos:vocabularyPlugins, skosmos:usePlugin is not needed in configuration.

Backup and Log monitoring

It is recommended to prepare a backup of your installation before installing plugins (as well as updating, patching, etc), or to use a testbed server. You may also want to enable exceptions logging, as well as log to a file, and monitor both the Skosmos log file, as well as the web application and system logs for any unexpected error.

Finally, as some resources load JavaScript and CSS files, comparing the browser console before and after installing a plugin can also be very helpful.

Example Plugin

In this simple example, we will display a message above the main area Skosmos, between the top menu, and the area where concepts and the hierarchy tree are displayed.

First, create a folder, for example "acrobata" under the Skosmos/plugins folder. Also add the plugin.json file, with the following content.

{
    "js": ["widget.js"],
    "css": ["stylesheet.css"],
    "templates": ["template.html"],
    "callback": ["acrobata_message"]
}

Now we will go through each resource file used in this plugin. First the JavaScript file "widget.js".

// declaring a namespace for the plugin
var ACROBATA = ACROBATA || {};

ACROBATA = {
	// variables in this namespace won't conflict with other global variables
	message_value: "This is an example message.",

	// likewise, functoins here also won't conflict with other existing functions
	render: function(date) {
		var source = $("#acrobata-template").html();
		var template = Handlebars.compile(source);
		var data = {
		  message: this.message_value + ". The time is " + date
		};   
                $("#content-top").append(template(data));
                // if you want to place plugin below concept or vocabulary info use this instead:
                // $('#content-bottom').append(template(data));
	}
};

$(function() {
	// call a function in the plugin namespace
	ACROBATA.render(new Date());

	// avoid polluting global namespace, or use meaningful and less likely to collide names
	window.acrobata_message = function() {
		console.log('This is executed for each page, once loaded');
	};
});

This file contains a few best practices for JavaScript, such namespaces. But you are free to implement the code as necessary for your environment.

The code above also contains the callback definition. Right near the end, where we define the global acrobata_message function. Note that it matches exactly the name of the callback declared. It will be executed for each page that is loaded.

The JavaScript code is also rendering a template, with Handlebars, a JavaScript library for templating. The template file looks as follows.

<h1 class='acrobata_message'>{{ message }}</h1>

The {{ message }} is replaced by the variable message passed in the data map, when the template is eval'ed. Notice how the template ID is created, as explained in the previous sections.

Finally, the stylesheet file.

/*
 * Be aware values here may impact other parts of the template. Use
 * good names, that won't affect other plugins or the rest of Skosmos.
 */
.acrobata_message {
	color: red;
}

Putting it all together, the plugin is complete. We just need to enable it. Modify the config.ttl file, making sure the globalPlugins property loads the plugin.

:config a skosmos:Configuration ;
  # ...
  skosmos:globalPlugins ( "acrobata" ) .

Load Skosmos, and you should now have a custom message being displayed, as well as the callback message in the browser console.

plugin-example

Other plugins

Search for Skosmos plugins created at NatLibFi (they are all named according to the pattern Skosmos-widget-*)

Clone this wiki locally