Setting up TinyMCE with jQuery and CakePHP 1.2

CakePHP uses the Prototype Javascript library for its ajax helper class but I've come to prefer jQuery. Prototype is a fine library too but I've just gotten used to jQuery.

A web application I'm working on needed a ttw html editor so I grabbed TinyMCE and copied in some of the example code and everything seemed to work fine at first glance. Unfortunately TinyMCE has an issue with jQuery's $(document).ready function and it also has an issue with saving via ajax in CakePHP.

There's a helpful page on the Bakery that outlines some issues you'll run into trying to get CakePHP & Prototype working with TinyMCE but it's a little out of date now (I'm using CakePHP 1.2RC1, TinyMCE 3.09 and jQuery 1.2.6 at the moment). I'll go through examples that illustrate how I solved the two problems I ran in to but I'm not going to explain everything you need to do ajax submissions with CakePHP.

jQuery's $(document).ready(function() runs before TinyMCE would like

For my first test with TinyMCE I just copied the code from the example and had something like

  mode : "textareas",
  theme : "advanced"

In it's own Javascript block. When using jQuery, most code should sit inside a call to $(document).ready(), so I tried moving it there and it broke. Instead, I set the mode to none for TinyMCE.init() and called execCommand() inside $(document).ready(), like so:

// init isn't happy inside the ready function
  mode : "none",
  theme : "advanced"
// the jQuery $().ready function runs later
  tinyMCE.execCommand('mceAddControl', false, 'ModelField');

(where ModelField is the model name then the field name - the id of your textarea)

Now tinyMCE.init() runs when it wants to as the document loads but it doesn't try to take over the textareas until execCommand() is called when the document is ready.

There could be a few variations on this depending on when you want TinyMCE to load. You can have a toggle function - I did one using jQuery:

<input type="button" name="mceToggleButton" id="mceToggleButton" value="Edit mode" />;
$("#mceToggleButton").toggle( mceOn, mceOff);
// turn on the rich editor
function mceOn() {
  tinyMCE.execCommand('mceAddControl', false, "ModelField");
// turn off the rich editor
function mceOff() {
  tinyMCE.execCommand('mceRemoveControl', false, "ModelField");

The TinyMCE Editor isn't your textarea, so there's no content when the form is gets posted
Whether you use ajax or not, TinyMCE is actually a bunch of other stuff that's replaced your textarea, not the textarea itself. That means that when you submit your form, the textarea is submitted with different contents than the editor has (or just nothing at all if you did all the editting in TinyMCE). To handle this, all you need to do is get the contents of the editor and stuff it into the vanilla textarea before you submit the form.

My code looks a lot like this:

// if there's an editor, get a reference to it
ed = tinyMCE.getInstanceById('ModelField');
if (ed) {
  // copy the contents of the editor to the textarea
// submit the form, I use $.ajax instead of $.post because I want to handle errors
$.ajax({ type:'POST', url: postUrl,
  data: $("#ModelActionForm").serialize(),
  success: function(a) {
    recordId = eval(a).id;  // see below
    // TODO: update your 'document saved' indicator here
  error: function(a) {
    // TODO: indicate save failed here

When the ajax request succeeds, I send the model id back in a json message like
(<?php echo $javascript->object(array('saved'=>$saved,'message'=>$message,'id'=>$id)); ?>)

The line recordId = eval(a).id; in my success callback makes the id available for subsequent calls to the edit action (the first call is to the add action).

Your rating: None

Thank you for confirming my suspicion that TinyMCE can't be set up in $(document).ready()!!