surevine bg

Extending TinyMCE – Part 1

Return to Resource Centre

10 October 2011

Guest Blogger

As I’m sure almost anyone who has been involved in web based applications will know TinyMCE is a rich text editor which can be embedded in a web page to allow a user to produce HTML.

TinyMCE also has a plugin architecture which allow you to easily add new functionality to it. Having used TinyMCE extensively in many projects, but only ever using the out of the box plugins which it ships with, I decided to get my hands dirty and see what’s involved in creating my own plugin.

The examples here are all based on the example plugin supplied with TinyMCE. In my next blog post I’ll be creating a new plugin with some actual functionality!

Getting Started

The first thing involved was to get a copy of TinyMCE for development. The way I chose to do this was to clone the TinyMCE development repository from github:

> git clone https://github.com/tinymce/tinymce.git tinymce

If you look in that directory there is a directory named “jscripts”. This is where the source for TinyMCE resides.

Inside the “jscripts” directory is a directory named “tiny_mce” and in that is a directory named “plugins”. This is where the plugins live. Installing a plugin is as simple as adding the plugin into that directory.

If you look again at the root of the project you will see there is also a directory named “examples”. In there is an HTML file name “full.html”. This is a good place to point your browser to test your TinyMCE code.

NOTE: Most browsers (with the exception of IE) will not let you run javascript from files directly from the hard disk, so you will need to access them through a web server such as apache. Setting this up is beyond the scope of this post, but you may like to look at WAMP for Windows, or MAMP for Mac OS.

The anatomy of a TinyMCE plugin

A plugin consists of, at the very least, a directory and a javascript file. The directory should have the same name as the plugin and should contain a javascript file named “editor_plugin.js”. It is this file which provides the entry point for the plugin’s code.

You will notice that the plugins provided with TinyMCE have both a “editor_plugin.js” and an “editor_plugin_src.js”. This is because the TinyMCE build process minifies the *_src.js file. For development we will only be working on the “editor_plugin_src.js” file which is the one used by the example pages.

Plugins which display a dialog will also have an html file and a javascript file to handle the dialog. The html file should sit in the root of your plugin directory and be named something useful (such as dialog.html) and the javascript should sit in a directory named “js” within your plugin directory.

Creating the Plugin

Thankfully, TinyMCE comes with an example plugin helpfully named “example” so the first thing to do is to copy and rename this directory into the plugins directory.

If you open the “editor_plugin_src.js” file within your newly created plugin then we can start to customise it.

The first thing to do is update all the references from “example” to our new plugin name “distribution_label” (not the line numbers may be different if the example plugin has been changed)

  • Line 13: tinymce.PluginManager.requireLangPack(‘example’)
  • Line 15: tinymce.create(‘tinymce.plugins.ExamplePlugin’
  • Lines 71-79: This is the plugin info – update it as appropriate
  • Line 83: tinymce.PluginManager.add(‘example’, tinymce.plugins.ExamplePlugin); <- This should match the class name at Line 15

Now I’m not going to go through every single change I made with a fine-toothed comb, but I will outline the more interesting parts.

Brief introduction to the TinyMCE API

TinyMCE has a rich and well documented API to allow developers to interact with the editor instance.

The main object you will interact with is the Editor object.  This is passed into your plugin’s init() method and gives you access to the editor panel’s DOM document  (and iframe window).

Note that because the TinyMCE editor does live inside an iframe you will need to use the document from Editor.getDoc(), not the main browser window.document to create DOM nodes which are to go inside the editor content (or use the handy DOMUtils utility class which has handy methods for creating nodes)

It also contains some utility classes: most usefully, within a property named dom, is an instance of the DOMUtils class which contains many useful methods to ease interaction with the DOM such as changing attributes and classes, and creating and manipulating DOM nodes.

It’s well worth having a delve into the API documentation as there is some great stuff in there. It’s also worth checking out the reference section which lets you know the standard set of TinyMCE commands (more on these later) and plugins available.

Adding toolbar buttons

Almost all plugins will probably interact with the user through toolbar buttons or controls. Adding a toolbar button is straightforward. All you need to do is place something like this in you plugin’s init() method:

ed.addButton('example', {
  title : 'example.desc',
  cmd : 'mceExample',
  image : url + '/img/example.gif'
});

The first parameter passed to the method defines the button name. This will be used to add the button to the toolbar (see the next section).

The second parameter is a configuration object. In this case it is defining the following properties of the button:

  • title : This is the key in the language pack (in langs/en.js) to use for the button title. Your button should have a title defined, even if you only intend to have an icon on your button, for users of assistive technology.
  • cmd : This is the command to call on the editor object when the button is clicked. I will get onto how to define commands next.
  • image : This is the path to an icon to use as the button’s image. url is the plugin’s url (which is passed into the init() method by TinyMCE).

The Editor.addButton() method used here is actually just a convenience method of adding buttons without dealing with the ControlManager directly (the class which is responsible for the UI controls).

Configuring TinyMCE with the plugin

TinyMCE is configured using a JavaScript object passed into the tinyMCE.init() method.

All we need to get our plugin loaded by TinyMCE  is to add it to the “plugins” property of the configuration object – it’s just a comma separated list of plugin names. Once this is added TinyMCE will call the init() method of our plugin when it is loaded. The plugin name should be the same as defined in the first parameter to the call to tinymce.PluginManager.add()

To get our toolbar button displayed requires another piece of configuration: Within the configuration object passed into TinyMCE are up to four properties named “theme_advanced_buttons1”, “theme_advanced_buttons2”, etc. These define the contents and order of the controls on the toolbars. These also have counterparts “theme_advanced_buttons1_add”, etc. which can be used to add buttons to the default toolbar layouts without having to redefine them.

Getting our button displayed on the toolbar is as simple add adding it to one of the existing toolbar definitions. Our configuration then becomes something like:

tinyMCE.init({
        mode : "textareas",
        theme : "advanced",
        plugins : "example"
        theme_advanced_buttons3_add : "example"
});

Defining an editor command

TinyMCE provides an event bus pubsub style construct to allow plugins and the TinyMCE core to interact with each other. By defining something as a TinyMCE editor command, any plugin can invoke a command on another plugin without having to have a dependency on each other. The TinyMCE core also provides a set of standard commands which can be invoked.

A command is usually defined in the plugin’s init() method like so:

ed.addCommand('mceExample', function() {
  // do some stuff
});

This has the following elements:

  • ed.addCommand : This is the method to call on the editor object to add a command.
  • ‘mceExample’ : This is the name of the command. This will be used by code wanting to invoke this command.
  • function() {} : This is the function which will be called when the command is invoked.

Displaying a dialog

One of the other things you will commonly want a plugin to do is to display a dialog to the user to get some input from them. The first thing you will need is an html document to display inside the dialog. Most commonly this will live in the root of your plugin folder. Give it a useful name too which relates to its function.

To display the dialog it is a simple case of calling open() on the WindowManager object (which we can get a reference for from the editor object). It looks like this:

ed.windowManager.open({
  file : url + '/dialog.htm',
  width : 320 + parseInt(ed.getLang('example.delta_width', 0)),
  height : 120 + parseInt(ed.getLang('example.delta_height', 0)),
  inline : 1
}, {
  plugin_url : url, // Plugin absolute URL
  some_custom_arg : 'custom arg' // Custom argument
});

The first object passed to the open method are the window options:

  • file : This is the path to the dialog html template file
  • width / height : These define the size of the dialog in pixels. In this case an extra fudge factor has been given to them from the internationalisation strings so that the dialog can be resized for different languages (which may need more or less room than the default).
  • inline : This tell TinyMCE to display it as an inline popup within the page rather than as a separate browser window. In order for this to work the inlinepopups plugin needs to also be loaded into TinyMCE.

The second object passed is a set of parameters to pass in to the dialog. These will then be available to the script running inside the dialog.

Putting it all together

Putting these bits and pieces together we can define a plugin which adds a button to the toolbar and displays a dialog when the button is pressed:

editor_plugin_src.js

(function() {
  // Load plugin specific language pack
  tinymce.PluginManager.requireLangPack('example')

tinymce.create('tinymce.plugins.ExamplePlugin', {

init : function(ed, url) {
  ed.addCommand('mceExample', function() {
    ed.windowManager.open({
      file : url + '/dialog.htm',
      width : 320 + parseInt(ed.getLang('example.delta_width', 0)),
      height : 120 + parseInt(ed.getLang('example.delta_height', 0)),
      inline : 1
    }, {
      plugin_url : url, // Plugin absolute URL
      some_custom_arg : 'custom arg' // Custom argument
    });
  })

  // Register example button
  ed.addButton('example', {
    title : 'example.desc',
    cmd : 'mceExample',
    image : url + '/img/example.gif'
  });
}

getInfo : function() {
  return {
    longname : 'Example plugin',
    author : 'Some author',
    authorurl : 'http://tinymce.moxiecode.com',
    infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example',
    version : "1.0"
  };
}

});

// Register plugin tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin); })();

Making sure it’s accessible

The developers of TinyMCE have put a lot of effort into making their product accessible to assistive technology users, so any plugins which you develop should follow the same idea. There’s not much in what we’ve done so far that will affect accessibility one way or another, but in my next post I will be delving a bit deeper into how we can make our plugins as accessible as the rest of TinyMCE.

Next Time

In my next post I’ll be looking at how we can add some logic to all this and make it do something useful including reading and updating editor contents.

Company

Surevine Limited

Registered in England and Wales with number 06726289

Registered Office

125 Wood Street, LONDON EC2V 7AW, United Kingdom

Find Us

Get in touch, we’d love to hear from you.

Useful Links

Surevine Logo
surevine security innovation of the year
Cyber Essentials Certified
Joscar Registered
LRQA Certified

© 2024 Surevine All rights reserved

LegalPrivacyCookie policyAccessibilityResponsible disclosure policy