Advanced examples - lokothodida/ckeditor-plugin-template GitHub Wiki
CKEditor dialogs are wrapped in an enormous number of <div>
s, <span>
s and <table>
s in order to maintain their appearances. The UI elements are built using the logic of the editor rather than the developer (i.e. you do not need to write out the markup for a text field to put a text field into your dialog). CSS IDs are generated dynamically, and this leads to the problem that styling an individual plugin's dialog can be very cumbersome.
Luckily, the boilerplate makes this process a bit easier.
...
// tabs
contents: [ /**/ ],
// fired when the dialog loads for the first time
onLoad: function() {
// add id for easier styling of elements in the dialog
$(this.getElement()).attr('id', plugin.dialog);
},
...
This takes the main dialog <div>
and gives it the id plugin.dialog
(which you defined in the plugin
object in the your-plugin/plugin.js
file (e.g. yourPluginDialog
). You can thus namespace your CSS from this id to ensure that the only elements affected are ones in your dialog:
#yourPluginDialog {
/* main dialog */
}
#yourPluginDialog input {
/* all input fields in your plugin's dialog */
}
The CKEDITOR.scriptLoader.load()
method allows you to load scripts asynchronously. You must be careful with your code however, as the methods and variables from those scripts may not be immediately available.
var defaultValueAttribute1 = 'Some text';
...
// attribute-1 field
{
// ...
id: 'attribute-1',
default: defaultValueAttribute1; // ReferenceError: defaultValueAttribute1 is not defined
// ...
},
...
An error thrown here will prevent the dialog from loading altogether. You must wait for the dialog to load for the variables to safely exist without throwing errors.
...
// attribute-1 field
{
// ...
id: 'attribute-1',
className: 'attribute-1', // for selecting the field more easily
onLoad: function() {
$('#' + plugin.dialog + ' .attribute-1 input').val(defaultValueAttribute1);
},
// ...
},
...
So to safely use your loaded scripts, only use those variables in the onLoad()
method of the main dialog and dialog fields.
It is also worth noting that variables loaded with CKEDITOR.scriptLoader.load()
are put into the global scope. To avoid clashes with other scripts and other plugins, either:
- Keep your variable names descriptive
- Namespace your variables
- Use immediately invoked expressions to shield way possible clashes and only push the required variables/functions into the global scope
If you are running procedures in your dialogs that take more than a few lines (and particularly if the code is going to be repeated elsewhere), it makes sense to wrap up that procedure in a function
. As noted above, if you load the function with the scriptLoader
, it will be put into the global scope, and possible solutions to name-clashing are given.
In the your-plugin/js
folder, you will have a helper object that is namespaced by YourPlugin
which you can safely add methods to. The API describes how to set up this object.
var _YourPlugin = function(path) {
...
this.yourMethod = function(/* params */) {
/* */
};
...
};
...
// fields
...
{
// description field
id: 'description',
type: 'html',
html: '',
className: 'description', // for selecting the field more easily
onLoad: function() {
YourPlugin.yourMethod(/* params */);
},
},
...
You may want to use jQuery UI or various other plugins to improve the UI elements of CKEditor and provide more functionality to your fields (e.g. a datepicker or improved dropdowns).
Simply load the script with the scriptLoader
, then apply the functionality in the onLoad()
method definition.
...
// load jQuery UI css
CKEDITOR.document.appendStyleSheet('//code.jquery.com/ui/jquery-ui-git.css');
// load jQuery UI script
CKEDITOR.scriptLoader.load('//code.jquery.com/ui/1.11.1/jquery-ui.js');
...
// your field
{
// ...
id: /* */,
type: 'text',
className: 'some-attribute', // for jQuery selector below
onLoad: function() {
$('#' + plugin.dialog + ' .some-attribute input').datepicker(/* */);
},
// ...
},
...
CKEditor provides an 'html' field type that lets you provide your own HTML markup in place of a field.
...
// field example
{
...
id: /* */,
type: 'html',
html: /* your html string */,
...
},
...
It is messy to have to deal with HTML markup as a string inside of JavaScript (i.e. concatenating a series of strings). Ideally, one would want to keep the HTML completely separate. This is possible by using AJAX to call your desired HTML file. Put the HTML in your-plugin/html/
and do the following:
...
// field example
{
...
id: /* */,
type: 'html',
className: 'your-html-field', // used for jQuery selector below
html: '',
onLoad: function() {
// path is defined at the beginning of the main.js file
var file = path + 'html/your-html-markup.html';
// ajax loads the contents of the file into the div
$('#' + plugin.dialog + ' .your-html-field').load(file);
}
...
},
...
If you wish to load the HTML synchronously instead:
...
// field example
{
...
id: /* */,
type: 'html',
className: 'your-html-field',
html: '',
onLoad: function() {
// path is defined at the beginning of the main.js file
var file = path + 'html/your-html-markup.html';
// ajax loads the contents of the file into the div
$.ajax({
url: file,
dataType: 'html',
async: false,
success: function(html) {
$('#' + plugin.dialog + ' .your-html-field').html(html);
},
error: function() {
// error handling (e.g. display an error for your user)
},
});
}
...
},
...
The API also describes how to use the helper YourPlugin
object's getHTML()
method to achieve this.