Thursday, February 18, 2010

TinyMCE and jQuery: The onLoad conundrum

In a recent project, I've had the challenge of trying to get the usage of a WYSIWYG editor, TinyMCE to actually be WYSIWYG by applying the styles that are used on the website within the editor itself.

This was relatively easy. I have an id attribute called #contentpad that contains most of the content that users are allowed to edit. So I updated my tinyMCE init options to include my public.css, and then I made sure that where ever I used #contentpad, I also used .mceContentBody. I did have to update a few other elements to suite, since styles applied to body for the website were not necessarily appropriate for applying to the body of the TinyMCE iframe.

It's not the tidiest of solutions, since I know I'll run into troubles if I ever switch WYSIWYG editors (I've been having a gander at CKEditor).

The next bit was harder. A part of making the editor closer to WYSIWYG is adjusting the width of the editor so it is more like what is available on the actual website. The thing is, we have a couple of spots where the width can vary.

The solution is simple enough once TinyMCE is loaded. We already had a solution to use jQuery to monitor the selection of a checkbox to change the width, after the TinyMCE editor was loaded.

$(document).ready(function(){
 
 // check when clicking the option
 $('#UnpublishedContentSetWidthForDualHomePage').click(function(){
  
  if ($(this).attr('checked')){
   $('#UnpublishedContentContent_tbl').css('width','402px');
   $('iframe#UnpublishedContentContent_ifr').contents().find('.mceContentBody').css('width', '366px');
  } else {
   $('#UnpublishedContentContent_tbl').css('width','802px');
   $('iframe#UnpublishedContentContent_ifr').contents().find('.mceContentBody').css('width', '766px');
  }
 }); 
});


However, the bit of code we had to check apply the same setting when the page was first loaded did not work.

 $(document).ready(function(){
  
  // check when first time on the page
  if ($('#UnpublishedContentSetWidthForDualHomePage').attr('checked')){
   $('#UnpublishedContentContent_tbl').css('width','402px');
   $('iframe#UnpublishedContentContent_ifr').contents().find('.mceContentBody').css('width', '366px');
  }
 });


There were many suggestions out there, like having Javascript in the iframe to notify when it had loaded, or load the iframe via jQuery, or even use LiveQuery. However, none of them really suited, since I had no control over the iframe.

Eventually, I found a reference to the TinyMCE oninit config item that will run a Javascript callback when the editor has finished loading.

So I wrapped the above code in a tinyMCECallback() function, and added the oninit property to the TinyMCE config, and it worked! Make sure you don't include the parentheses in the oninit call (i.e. oninit : "tinyMCECallback"), and make sure you include the callback code before including the tinyMCE.js.

Just as a note for the numbers used in my widths. The physical width available on the public website is 800px, so I added 2px to cater for the TinyMCE margins. The available content space actually has a margin of 17px either side, to I set the .mceContentBody to cater for this, and reduced it to 766px. This makes the editor look a bit more natural, with regards to the margins.

1 comment:

  1. Thank you, Rueben. I have been searching for many hours to find a way to run a javascript function (to change the background color, dependent on a session variable) after my tinyMCE frames are loaded. This is such a simple solution, yet I could not find it anywhere!

    ReplyDelete