The core architecture of ActiveUI is based on a global state, which is a single plain JavaScript object containing all the information needed to render the page. Building an application with such an architecture has a lot of theoretical benefits:
So this large plain JavaScript object is convenient because we have a human readable JSON that completely describes the state of the application. Now this has an obvious implication: every piece of information we need to render must be storable in this plain JavaScript object and therefore must be serializable. So it has to be a tree of primitive types like booleans, strings, numbers, arrays, or hashs. This excludes one main type in JavaScript: functions. Functions cannot be converted to a serializable representation because they are more than the string representation of their body: they often refer to external variables (called closures).
This is painful for us because we are writing a library, with a lot of entry-points to let users customize what happens when a given event arises. So a project would like to override for instance what happens when a user double clicks on a cell of a Tabular View. The natural way of describing this would be to give a function to our Tabular View configuration and we would execute this function when double clicking on a cell. Sadly we can’t do that because when we display the Tabular View the only source of information we can read from is the global state which cannot contain functions.
This is why we introduced the concept of Plugins. The principle is that, in your project code, you can register objects with methods by giving them a key, and then these keys can be used inside the global state to refer to the function. This has a few impact regarding the list of benefits of the global state:
As opposed to ActivePivot Server, plugins and serialization are really close concepts. We created plugins to be able to serialize functions. So creating a plugin is similar to defining an object with methods and indicate how it should be serialized.
In order to register your own plugin implementation, use:
activeUI.plugins.register({
type: 'cell-editor',
key: 'my-cell-editor',
createProperties(parameters) {
return {
myProperty(cell) {
// do stuff
}
};
},
staticProperties: {
myStaticProperty: true
}
});
The register function takes only one argument and it is of type PluginDescription.
The couple (type, key) should be unique among your project otherwise some plugins will override others.
If you deliberately want to override the implementation of a core plugin use activeUI.plugins.override
.
The plugins are referenced within the configuration of a widget, for example a tabular view/pivot table. Within that configuration, a plugin can be referenced in two ways: as a string or as an object.
When no arguments are required, there are three equivalent ways of defining a plugin:
// Defining 'my-cell-editor' cellEditor plugin as a string
const tabularViewConfiguration = {
cellEditors: ['my-cell-editor']
};
// Defining 'my-cell-editor' cellEditor plugin as an object with no parameters
const tabularViewConfiguration = {
cellEditors: [
{
key: 'my-cell-editor'
}
]
};
// Defining 'my-cell-editor' cellEditor plugin as an object with an empty args parameters
const tabularViewConfiguration = {
cellEditors: [
{
key: 'my-cell-editor',
args: {}
}
]
};
When arguments are provided/required and part of the plugin definition, the plugin is defined as:
// Defining 'my-cell-editor' cellEditor plugin as an object with args parameters
const tabularViewConfiguration = {
cellEditors: [
{
key: 'my-cell-editor',
args: {arg1: 'myArgument1', arg2: 42}
}
]
};
Note: The two ways are always valid, but only the second one allows to send parameters to the plugin.
The list of public plugins is available here.