Skip to content
fredck edited this page Dec 15, 2014 · 12 revisions

While the CKEditor 5 Framework (core) brings the basic infrastructure to create and manage editors, plugins make them visually interactive and feature rich.

Installing Plugins

CKEditor 5 plugins are available through npm. To install them into a clone of the ckeditor5 repository, simply execute the following in the command line:

npm install --save ckeditor5-plugin-<plugin name>

The --save option will instruct npm to include the plugin inside the dependencies block of the package.json file. This is important if you are planning to include the plugin inside editor builds.

An additional way to include plugins is by simply add a <script> tag to your page, pointing to the main plugin module file. This requires additional configuration though (see The Plugin Path below).

Plugin Development

Each plugin should be coded into a dedicated environment, ideally using Git and GitHub.

To unify all different plugin projects and to make the build process simpler, the following conventions should be adopted.

Folder structure

The plugin project should be based on the CKEditor Boilerplate repository. This raises the overall quality of the code by giving a standard format to it.

Additionally:

  • src/ - contains all files required by the plugin, including resources. Except for the main script file and its AMD dependencies, everything available here will be copied to the build/plugins/<plugin name>/ directory during the build process.
  • src/<plugin name>.js - the main plugin module.
  • tests/ - plugin specific tests.
  • package.json - other than common meta information, it contains the plugin's full name, its version and dependencies (usually pointing to other plugins). The builder may use this file in the future.

Naming convention

Plugins should use the following naming convention:

ckeditor5-plugin-<name>

... where <name> is the unique name of the plugin and must be used to name the main plugin script (src/<name>.js).

Example:

ckeditor5-plugin-example/
  src/
    images/
    example.js
  package.json

Main Plugin Module

The entry point of a plugin is a JavaScript file having its name. It defines a module with the following template:

CKEDITOR.define( 'plugin!example', [ 'plugin' ], function( Plugin ) {
    return Plugin.extend( {
        init: function() {
            // Initialization function.
            // The following extras are available:
            // this.name;
            // this.path;
            // this.editor;
        }
    } );
} );

The Plugin Path (this.path)

The path property is injected into the plugin instance while initializing it. By default, the injected value will be created by the CKEDITOR.getPluginPath() function. This will return the proper path depending on the environment:

  • dev: basePath + ../node_modules/ckeditor5-plugin-<name>/src/
  • build: basePath + plugins/<name>/

However, for plugins included with <script> tags, it is necessary to inform CKEditor about the plugin path. This can be done through the editor configuration:

CKEDITOR.create( '#editor', {
    plugins: [
        'foo', 'bar', { name: 'custom', path: 'path/to/custom/' }
    ]
} );

Dependencies

Plugin dependencies may happen. To specify this, two things are necessary (for example plugin A depends on B):

  1. Include the dependency into package.json: npm install --save ckeditor5-plugin-b.
  2. Include the dependency in the CKEDITOR.define call of the plugin module:
CKEDITOR.define( 'plugin!a', [ 'mvc/plugin', 'plugin!b' ], function( Plugin ) {
    return Plugin.extend( {
        init: function() {
            // Code goes here.
        }
    } );
} );

Exposing Plugin Methods

By using the AMD features, it is possible to expose plugin features though methods in two ways, as shown in the following example:

CKEDITOR.define( 'plugin!example', [ 'plugin' ], function( Plugin ) {
    var plugin = Plugin.extend( {
        init: function() {
            ...
        },
        
        // Exposes a feature as an instance method.
        someInstanceMethod: function() {
            ...
            // Has access to this.editor, etc.
        }
    } );
    
    // Exposes a feature as a static method.
    plugin.someStaticMethod = function() {
        ...
    };
    
    return plugin;
} );

Other plugins can use these features in this way:

// Add "example" as a dependency. This makes the static methods available as well as
// guarantees that "example" will be initialized before "otherplugin".
CKEDITOR.define( 'plugin!otherplugin', [ 'plugin', 'plugin!example' ], function( Plugin, Example ) {
    return Plugin.extend( {
        init: function() {
            // Call the feature exposed in the plugin instance.
            this.editor.plugins.example.someInstanceMethod();
            
            // Call the feature exposed as a static method.
            Example.someStaticMethod();
        }
    } );
} );

Plugins Initialization

Each editor may have a different set of plugins enabled. This is defined through its configuration:

CKE.create( '#editor', {
    plugins: 'A,B,C,D,E'
} );

Each plugin module returns a class which is then instantiated for each editor using it. Following that, the init() method of the plugin instance is called.

CKEditor guarantees that plugins are initialized in their dependency order. In the above example, let's suppose that A depends on X (not in the configuration) and B depends on C. In such case, the plugins will be initialized in this order: X, A, C, B, D, E.

Asynchronous Initialization

TODO: The information in this session is outdated. Asynchronous initialization will be done with promises.

If a plugin initialization is asynchronous, it is enough to include the done parameter to the init() method, so the editor gets notified about it. For example:

Plugin.extend( {
    init: function ( done ) {
        setTimeout( function () {
            // Async stuff.
            done();  // Callback when ready.
        }, 1000 );
    }
} );

Warning: If you don't want to initialize a plugin asynchronously, then do not specify the done parameter.

Clone this wiki locally