30 June 2010

CKEditor Context Menu

This is a short how-to on how insert a context menu in CKEditor. It's not hard, but now it's still undocumented.

What you have to do

A short reference for who already knows (or wants to figure out) how to do these steps.
  1. Create a regular command (as the UI button commands).
  2. Create a group for your menu' items.
  3. Create an item and add it to the menu'.
Details
A more detailed explanation... With code and plugin example ;)

CKEditor have two plugins: menu and contextmenu.
The first plugin defines the primitives (menu, group and item) that allow CKEditor to have menus. A menu is a container (in detail, a floatpanel, which is provided by another plugin) which can be placed anywere in your editor and contains a list of items, divided in groups. Every item has a name, a label and an associated command to it. AFAIK, the menu plugin doesn't imply anything else than this (definition and rendering). This means that menu bars and context menus aren't handled anyway by this plugin.

The contextmenu plugins requires the menu plugin, and it's pretty short: it's responsibility is only to check if the menu items shall be shown in a particular context. In other words, when you ask for a context menu (probably right clicking), some listener functions are called to check what items goes in the menu. These listener functions are registered in each plugins (so, each plugin has a listener function for the context menus).

In general, a plugin will register many menu items, and when a context menu is asked, the listener will return which items to show.

Let's see an example: I'll create a plugin that executes an arbitrary code when an item is clicked.

First: create the plugin: plugins/myplugin/plugin.js

CKEDITOR.plugins.add('testplugin', {
  init: function(editor) {
  alert("Ok");
  }
});

and load it in your config.js (load multiple plugins by comma separating them in the string)


CKEDITOR.editorConfig = function(config) {
  config.extraPlugins = 'testplugin';
};

This plugin shall load correctly and alert an "Ok". If not, search elsewhere details on plugin loading :P
First step, is to define a command to execute. Here a dummy command:

CKEDITOR.plugins.add('testplugin', {
  init: function(editor) {
  editor.addCommand('testcommand', {
      exec: function(editor) {
  alert("Ok");
  }
  });
    editor.execCommand('testcommand');
  }
});

The command shall be added and executed, and another "Ok" shall appear. If not, scream loudly :D

Now we'll create a context menu capable of executing that command. Replace execCommand with this:

if (editor.addMenuItem) {
  // A group menu is required
  // order, as second parameter, is not required
  editor.addMenuGroup('testgroup');
  // Create a manu item
  editor.addMenuItem('testitem', {
label: 'Do something',
  command: 'testcommand',
  group: 'testgroup'
  });
}
if (editor.contextMenu) {
  editor.contextMenu.addListener(function(element, selection) {
return { testitem: CKEDITOR.TRISTATE_ON };
  });
}

This code checks for the presence of the addMenuItem function in the editor (i.e. the plugin is loaded): if present, adds a group and a menu item. Note that the item have a name, a label, a command and a group. The next snipped checks if the contextMenu is present, and in that case, adds a new listener that always enables the testitem item in the menu list. The listener shall return a dictionary where keys are menu item names, and values are CKEDITOR.TRISTATE_X depending on your need. If null is returned instead of this dictionary, all items are not displayed by default (of course... Or it would be a mess!).

This shall produce an editor that clicked anywhere, pops up a context menu with our "Do something" item, that alerts an "Ok" when clicked.

It's done :) But to show you that this is actually about contexts and not about menus I'll add a check: if the context menu is asked on a bold text, then the voice will appear, else it won't.
Check out this new listener:

editor.contextMenu.addListener(function(element, selection) {
  // Get elements parent, strong parent first
  var parents = element.getParents("strong");
  // Check if it's strong
  if (parents[0].getName() != "strong")
    return null; // No item
  // Show item
  return { testitem: CKEDITOR.TRISTATE_ON };
});

Ok, done.
Stay --sync

11 commenti:

  1. Hi, Can i;m looking for this one :
    [code]var parents = element.getParents("strong")[/code]

    Because, In the a page i have somes forms and every form i have an instance CKEDITOR. When i submit form, i dont't know to check form will be submit data???
    I thinking my solution :
    [Code]
    instances = CKEDITOR.instances;
    for(var name in intances ) {
    var oEditor = CKEDITOR.instances[instances[name]];
    if(oEditor && oEditor.getParentForm() == 'form') {
    // oEditor.getDate() and submit...
    }
    }
    [/Code]
    ReplyDelete
  2. Hi, I saw your post in the forum. Please continue the discussion there: http://cksource.com/forums/viewtopic.php?f=11&t=19771
    ReplyDelete
  3. Hi Alessandro,

    Nice blog.
    I have a beginner question about the ckeditor.
    I really would like to use it,
    but I don't know how to start or launch the program.
    I read the user guide but it does not say how to do it.
    It seems to skip this part.

    I understand CKEditor is a text editor to be used inside web pages.
    I have uploaded the files to my website and tested the samples files OK.
    I use firefox 3.5 and it does not work with the demo page on the site.
    I tried to open the ckeditor.js file but got an error
    "windows script host" invalid charactor.

    Could you please briefly explain how to start the program either in firefox or IE.
    Your help is highly appreciated.

    Also, can I do run the program locally on my hard drive so I can test it before anyone can see on the internet.

    I really look forward to your help.

    Thank you.
    JOE
    ReplyDelete
  4. thanks, helped me a lot
    ReplyDelete
  5. @JOE, Awww sorry, didn't see your post before (or forgot to reply, sorry). I hope you figured it out, but there are some examples on how to use the ckeditor in different browsers.

    @Anonymous, glad it helped.
    ReplyDelete
  6. Perfect code. Could you help me and tell how can I to find out what the object I clicked?
    ReplyDelete
  7. I am sorry Peter, I stopped working ok CKEditor more than 1 year ago and I really can't remember :S
    A part of coming up with the obvious WRONG solution (global variable assigned every time you click the object... But BRRRR this is so wrong I'll take a shower), I can't recall anything specific. Watching the code, I could only think about having the object information in the listener parameters (element, maybe?).
    Sorry, I don't think I can help... Sorry.
    ReplyDelete
  8. This comment has been removed by the author.
    ReplyDelete
  9. Thanks AkiRoss for "element" I was a little tired. Right sentence is "element.is( '{html element name}' )".
    ReplyDelete