8. Handling the client side¶
DjangoCMS-Cascade is shipped with a lot of plugins, all having their own inheritance hierarchy. Due to the flexibility of Cascade, this inheritance hierarchy can be extended though some configuration settings, while bootstrapping the runtime environment. Some plugins for instance, can be configured to store some settings in a common data store. This in the admin backend requires a special Javascript plugin, from which the client side must inherit as well.
Hence on the client side, we would like to describe the same inheritance hierarchy using Javascript. Therefore Cascade is equipped with a small, but very powerful library named ring.js. It makes Javascript behave almost like Python. If a Cascade plugin provides a Javascript counterpart, then other Cascade plugins inheriting from the former one, map their inheritance hierarchy in Javascript exactly as provided by the plugins written in Python.
8.1. Implementing the client¶
Say, we want to add some client side code to a Cascade plugin. We first must import that Javascript
file through Django’s static asset definitions using the Media
class, or if you prefer in a
dynamic property method media()
.
At some point during the initialization, Cascade must call the constructor of the Javascript
plugin we just added. Therefore Cascade plugins provide an extra attribute named ring_plugin
,
which is required to name the Javascript’s counterpart of our Python class. You can use any name
you want, but it is good practice to use the same name as the plugin.
The Python class of our custom Cascade plugin then might look like:
from cmsplugin_cascade.plugin_base import CascadePluginBase
class MyCustomPlugin(CascadePluginBase):
name = "Custom Plugin"
... other class attributes
ring_plugin = 'MyCustomPlugin'
class Media:
js = ['mycustomproject/js/admin/mycustomplugin.js']
whereas it’s Javascript counterpart might look like:
django.jQuery(function($) {
'use strict';
django.cascade.MyCustomPlugin = ring.create({
constructor: function() {
// initialization code
},
custom_func: function() {
// custom functionality
}
});
});
After yours, and all other Cascade plugins have been initialized in the browser, the Cascade
framework invokes new django.cascade.MyCustomPlugin();
to call the constructor function.
8.2. Plugin Inheritance¶
If for instance, our MyCustomPlugin
requires functionality to set a link, then instead of
replication the code required to handle the link input fields, we can rewrite our plugin as:
from cmsplugin_cascade.link.config import LinkPluginBase
class MyCustomPlugin(LinkPluginBase):
... class attributes as in the previous example
Since LinkPluginBase
provides it’s own ring_plugin
attribute, the corresponding Javascript
code also must inherit from that base class. Cascade handles this for you automatically, if the
Javascript code of the plugin is structured as:
django.jQuery(function($) {
'use strict';
var plugin_bases = eval(django.cascade.ring_plugin_bases.MyCustomPlugin);
django.cascade.MyCustomPlugin = ring.create(plugin_bases, {
constructor: function() {
this.$super();
// initialization code
},
...
});
});
The important parts here is the call to eval(django.cascade.ring_plugin_bases.MyCustomPlugin)
,
which resolves the Javascript functions our custom plugin inherits from.
Note
In case you forgot to add a missing JavaScript requirement, then ring.js complains with
the error message Uncaught TypeError: Cannot read property '__classId__' of undefined
.
If you run into this problem, recheck that all Javascript files have been loaded and
initialized in the correct order.