I’ve just been spending some time adding dependency resolution to TinyMCE plugins.
The concept is that a plugin can depend on other plugins. As a part of doing this work I’ve had some good opportunity to dive deep into how plugins in TinyMCE work. It’s been a good little trip that I’ll summarise briefly here. I’ll do this by first presenting the lifecycle, then explaining how plugin dependencies will work.
Plugin Loading Lifecycle
The TinyMCE plugin loading lifecycle there are three concepts that are important to understand:
PluginManager.add This code should typically try to remain outside of the global namespace, executing within an anonymous function block, as per the code in the example plugin.
Plugins specified in the plugins attribute of the settings object will be loaded if they have not previously been loaded. Historically TinyMCE has also included a – prefix to prevent autoloading of plugins. This is no longer required, as TinyMCE is smart enough to know if a plugin has been loaded, and won’t load it twice. So in effect, there is no reason to include the – prefix (so the only part to remember from this paragraph is that plugins specified in the plugins attribute of the settings object will be loaded if they have not previously been loaded).
A plugin class can be added to TinyMCE using the PluginManager.add function, passing the short name of the plugin and the implementing class for the plugin. The short name should be a unique identifier for the plugin, and the plugin class provides the code that implements the plugin.
Importantly the class can provide an init method which will be called by TinyMCE when it is being initialised. The class should also provide a getInfo method which returns information about the plugin.
There are two ways of performing an add. It can either be done manually before loading TinyMCE, or it could be specified in the editor_plugin.js that gets loaded as a part of the load process above.
The init function of the class for a plugin will be called after TinyMCE has created the plugin, as a part of the editor initialisation process. The plugin will be passed a reference to the editor as a part of the initialisation process.
Plugin dependencies can/will be specified in an array parameter to the PluginManager.add function call. There are two ways to specify a dependency.
- as a string. String dependencies will reference the short name of the dependency. If the dependency has not previously been loaded, TinyMCE will attempt to load the dependency.
- as a simple object. The object will have the form:
These will then be concatenated together to form a url. URLs will be resolved as relative to the TinyMCE installation. In the above object this would generate the url: “url_prefix/name_of_plugin/path_to_file.js”
When specifying a plugin dependency, there is a guarantee that the init method of the dependencies will be called before the init method of the plugin. There is no guarantee of the order in which the plugin “editor_plugin.js” is loaded. This can be seen in the test “plugin_dependency_init_call_order.html” which shows the order in which the init method is called. That the loading of plugins is not specified as a part of the new dependencies work is somewhat intuitive. It is only as a part of the load process that a plugin (and it’s list of dependencies) are made known to TinyMCE, which means that it is not possible to specify dependencies within the plugin before loading the plugin. The init of plugins is only performed after the plugins have all been loaded, making it possible for the dependencies to be init’ed before a plugin is init’ed