Plugins
Presentation
Plugins bind JavaScript code to a string. They provide a method of referring to a set of properties and methods through a plugin key. It's the mechanism used to make customizations serializable and therefore persistable. Together with settings, plugins are the main extension point of ActiveUI.
Usage
Registering a Plugin Implementation
To register your own plugin implementation you can, for instance, use:
const activeUI = createActiveUI({
plugins: {
// `cell-editor` is the plugin type.
'cell-editor': [
// Array of `cell-editor` plugins you wish to register.
{
key: 'my-cell-editor',
createProperties(parameters) {
return {
myProperty(cell) {
// do stuff
},
};
},
staticProperties: {
myStaticProperty: true,
},
},
],
},
});
The plugins
option is a map with plugin types as keys and lists of ActiveUIPlugin
as values.
Referring to a Plugin Implementation
Plugins are often referred to within the configuration of a widget, for example a Tabular View or a Pivot Table. Within that configuration, a plugin can be referred to in two ways: as a string or as an object.
When no arguments are required, there are three equivalent ways of referring to a plugin:
// Referring to 'my-cell-editor' as a string
const tabularViewConfiguration = {
cellEditors: ['my-cell-editor'],
};
// Referring to 'my-cell-editor' as an object with no parameters
const tabularViewConfiguration = {
cellEditors: [
{
key: 'my-cell-editor',
},
],
};
// Referring to 'my-cell-editor' as an object with no parameters (empty args)
const tabularViewConfiguration = {
cellEditors: [
{
key: 'my-cell-editor',
args: {},
},
],
};
When a plugin accepts or requires parameters, it can be referred to as:
// Referring to 'my-cell-editor' as an object with 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 the passing of parameters to the plugin.
Available Plugins
The list of available plugins is here.
More Details About the Plugin Concept
The Global State
The 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 this type of architecture has many theoretical benefits:
- Undo/redo history: undo/redo is easily implemented as reloading a previous state object.
- Save and restore application state: it is possible to reload the application in the same state you left it, because the state cab be stored in the browser-persisted storage.
- Dynamic localization/theming: this enables re-rendering of the application with a different locale and theme, without having to reload the page.
- Collaboration: pieces of state can be synchronized through a remote server to "screen share" and collaborate with someone else's session on a specific widget.
- Bookmarking: each widget becomes "bookmarkable" because widgets are represented by a single plain JavaScript object that can be serialized as JSON.
- Bug reproduction: if something went wrong with the application, the global state can be dumped and attached to the issue along with a screenshot in order to understand and reproduce the issue (i.e. the current state dump could be sufficient to reproduce a bug).
- Advanced tweaking: it is possible to directly write into the widget's state to update certain parameters that have, for instance, no corresponding UI as yet.
The Issue
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 hashes. 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).
An Example
Suppose you would like to override 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. We cannot do that because at the time the tabular view is displayed, the only source of information we can read from is the global state which cannot contain functions.
The Solution
This is where plugins come into play. 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 an impact regarding the list of benefits of the global state:
- Collaboration: This will only work if both users are using the same project code. Otherwise they might have different implementations for the same plugin key which will lead to inconsistencies.
- Bug reproduction: we might need to have the code of your project plugins in addition to the global state if they are referred to in a place related to the bug.