Using TinyMCE with CakePHP
TinyMCE is a nice WYSIWYG web editor by Moxiecode, giving your users a very convenient way to edit HTML content. And guess what, its very easy to use it in your Cake apps !
What is TinyMCE ?
TinyMCE is a WYSIWYG editor by Moxiecode that you can find here : http://tinymce.moxiecode.comIts very fast to load (much faster than FCKEditor last time i've tried, which is quite a long time ago now, I must admit...), easy to setup and configure. It isn't as powerful as FCKEditor (http://www.fckeditor.net/) in terms of text processing, but if all you need is a small WYSIWYG editor to get clean (X)HTML, TinyMCE is your boy.
Installation
First step, of course, is to download TinyMCE. You can do this here : http://tinymce.moxiecode.com/download.php. At the time of writing, latest version is 2.0.6.1, and has been for a few months. 2.0.6.1 is very stable. Once downloaded, unpack TinyMCE, and copy just the tinymce/jscripts/tiny_mce folder in /webroot/js. You don't need the rest of the archive (documentation, examples, etc.) on your webserver.Configuration
Next step is to implement it in Cake. Its very easy. First, we need to add this to the layout(s) that will be used on the page(s) that will have the editor. Of course, you need to add the javascript helper to your $helpers array in your controller(s) :PHP Snippet:
Download code
<?php
if(isset($javascript)):
...
echo $javascript->link('tiny_mce/tiny_mce.js');
...
endif;
?>
Then, for each page that will have a TinyMCE editor, you'll have to add to the top of the view file :
HTML:
Download code
<script type="text/javascript">
tinyMCE.init({
theme : "simple",
mode : "textareas",
convert_urls : false
});
</script>
By default, there are 2 themes with TinyMCE : 'simple' and 'advanced'. You specify the one you want to use on your page with the theme parameter. You can create your own themes or modify the existing ones in the webroot/js/tiny_mce/themes folder. The mode parameter is set here to 'textareas', meaning that all textareas of the page will be replaced by TinyMCE editors of the same size. If this behaviour doesn't satisfy you, check the documentation (http://tinymce.moxiecode.com/tinymce/docs/option_mode.html). The last parameter, convert_urls, is set to false so that TinyMCE doesn't try to process URLs for images or links.
There are loads of other parameters (All documented here : http://tinymce.moxiecode.com/tinymce/docs/index.html) to customize the way the editor will work. For example, the file_browser_callback allows you to give a js callback function or method to call a custom file browser for the image insertion popup dialog.
If you want to change the way the text in the editor appears, each theme has a css/editor_content.css file that you can modify to match your site's styles.
Comments
Question
1 Is it really that simple
Should we add TinyMCE to the bakery?
Comment
2 Preventing duplicate code
Or even better: what i did is put those lines in an element, so that you can pass arguments to it if you want to call tinyMCE with some options (like theme, mode,...)
Question
3 Can you give me some example
Can you show me an (or some) example(s)?
Comment
4 example of using elements for DRY approach
app/views/elements/tinymce.thtml:
View Template:
<?php echo($javascript->link("tinymce/jscripts/tiny_mce/tiny_mce.js"));
?>
<script language="javascript" type="text/javascript">
<?php if($preset = "basic")
{
$options = '
mode : "textareas",
theme : "advanced",
theme_advanced_buttons1 : "bold,italic,underline,separator,justifyleft,justifycenter,justifyright, justifyfull,bullist,numlist,undo,redo,link,unlink",
theme_advanced_buttons2 : "",
theme_advanced_buttons3 : "",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_path_location : "bottom",
extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
content_css : "/css/'.$this->layout.'.css"
';
}
?>
tinyMCE.init({<?php echo($options); ?>});
</script>
then, whereever i need it in a view, i just call it like this
View Template:
<?php echo $this->renderElement('tinymce',array('preset' => 'basic')); ?>
the 'basic' preset if one i created myself, change or expand to your likings :)
Comment
5 This is a good idea
I guess I'm not DRY enough ;)
Comment
6 Its your call
Because even if WYSIWYG editors are great tools for the layman, its main drawback is that the generated HTML is most of the time VERY bad code, likely to break a carefully planned CSS layout, and prevent the page from validating correctly.
Comment
7 Simplify
if you create an additional theme, you should be able to take out editting features you don't want your clients to use. in a lot of cases all you'll really need is inserting urls, paragraphs, headings, bulletted lists. if you don't want your client to break your css, don't allow any font sizing or coloring.
Question
8 Tiny and AJAX
Was made follow this tutorial.
Why? Maybe anyone know ?
Comment
9 It is all in how Tiny works
I've found the same problem. Basically Tiny replaces the textareas with iframes. Upon Submit, it uses javascript to pull the values from the iframe and populates your original field before the form gets submitted.
This causes all sorts of errors when used with Ajax.
I am still working out the details, but the answer lies in passing a command in your ajax call to load tiny again. Once I've got it worked out, I'll post a tutorial.
Comment
10 About Tiny and AJAX
There is a solution. I posted a new tutorial(http://bakery.cakephp.org/articles/view/140) that covers TinyMCE and AJAX.
Hope it helps.
Comment
11 Correction to example code
should be
A small, but important difference.
Question
12 TinyMCE for beginners
I succeded in testing the blog tutorial, but not the use of the tiny MCE editor. Would you please help me?
1- According to the DRY advice, I created a file, 'tinymce.thml' in 'app/views/elements'
2- Then added the suggested links to the javascripts within the default layout i.e 'app/views/layouts/default.thml'; e.g
echo $javascript->link('tiny_mce/tiny_mce');
3- Finally, added the following line
renderElement('tinymce',array('preset' => 'basic')); ?> within my 'add' view i.e 'app/views/posts/add.thml'
But: it does not work properly
I have a message like this 'Error rendering Element: tinymce'
Comment
13 Forget WYSIWYG... Use WYSIWYM
Everyone should better use a WYSIWYM (what you see is what you MEANT) editor such as WYMeditor, that can be found here : http://www.wymeditor.org/. It's a powerfull tool that generates a beautiful code ;o)
Unfortunately, it supports only IE and gecko-based browsers, so if you're using Opera...
Comment
14 Use TinyMCE to build a WYSIWYM
Comment
15 DRY element with added spell check and GZ compression and Jquery
View Template:
<?php
/* SVN FILE: $Id$ */
/**
* Reusable element for creating an compressed tinyMCE editor, with jquery.
*
* This element expects 2 varables, $preset which determins the
* layout and features of the editor and an array $textareas which is
* list of the ID's to which the editor should be applied.
*
* Also the code uses the GZip compression to increase speed and the
* curl based google spell checker plugin.
*
* code taken from :
* http://wiki.moxiecode.com/index.php/TinyMCE:Compressor/PHP
* http://dev.jquery.com/wiki/Plugins/tinyMCE
* http://bakery.cakephp.org/articles/view/using-tinymce-with-cakephp
*
* PHP versions 5
*
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2006-2008, Alex McFadyen
* @link http://www.acmconsulting.eu acmConsulting
*
* @package app
* @subpackage views.elements
*
* @version $Revision$
* @modifiedby $LastChangedBy$
* @lastmodified $Date$
*
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
echo($javascript->link("tiny_mce/tiny_mce_gzip.js"));
?>
<script type="text/javascript">
tinyMCE_GZ.init({
plugins : 'style,layer,table,save,advhr,advimage,advlink,emotions,iespell,'
+'insertdatetime,preview,media,searchreplace,print,contextmenu,'
+'paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,'
+'xhtmlxtras,spellchecker',
themes : 'advanced',
languages : 'en',
disk_cache : true,
debug : false
});
</script>
<script defer language="javascript" type="text/javascript">
<?php
switch ($preset) {
case 'basic':
$options = '
mode : "none",
theme : "advanced",
plugins : "advhr,advlink,spellchecker,",
theme_advanced_buttons1 : "bold,italic,underline,separator,justifyleft,justifycenter,justifyright, justifyfull,bullist,numlist,undo,redo,link,unlink,spellchecker,",
theme_advanced_buttons2 : "",
theme_advanced_buttons3 : "",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "center",
extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
content_css : "/css/'.$this->layout.'.css"
';
break;
default:
$options = '
mode : "none",
theme : "advanced",
plugins : "advhr,advlink,spellchecker,",
theme_advanced_layout_manager : "SimpleLayout",
theme_advanced_disable: "hr,",
theme_advanced_buttons1: "pasteword,justifyleft,justifycenter,justifyright,justifyfull,separator,removeformat,separator,charmap,advhr,",
theme_advanced_buttons2: "styleselect,bold,italic,underline,separator,link,separator,bullist,numlist,outdent,indent,spellchecker,",
theme_advanced_buttons3: "",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
content_css : "/css/'.$this->layout.'.css"
';
break;
}
?>
$(document).ready(function(){
<?php
foreach($textareas as $id)
echo("\t\t$('#$id').tinymce();");
?>
});
$.fn.tinymce = function(options){
return this.each(function(){
// I don't think the style declaration is not really used in this sense, but I left it anyway
preString = "<div class='jqHTML_frame' style='width:"+$(this).css("width")+"px;height:" + ($(this).css("height")+20) + "px;'>";
postString = "</div>";
$(this).wrap(preString + postString);
// this comes last to avoid IE7 bug
tinyMCE.addMCEControl(document.getElementById(this.id), this.id);
});
}
function initMCE()
{
tinyMCE.init({ <?php echo($options); ?>});
}
// initialize tiny mce
initMCE();
</script>
Comment
16 TinyMCE integration
Comment
17 helpers
Hi there welcome and enjoy the magic..
i have started this several months ago ...
so if you have some questions, please do ask, i know the frustrations of the lack of good documentations
your question's answer :
in the controller use this
Class TestController extends AppController {
var $name = 'Test';
var $helpers = array('Html','Form','Javascript');
function index() {
... something ...
}
}
hope this helps abit
Comment
18 error javascript
using this code :
if(isset($javascript)):
...
echo $javascript->link('tiny_mce/tiny_mce.js');
...
endif;
?>
for include javascript, but I got error from my browser. the tinyMCE not present, cause my FireBug report error with this file (tiny_mce.js)
can I using javascripts with another way ?
thank's
sorry for my language
Comment
19 TinyMCE Helper
In your views, call TinyMceHelper::init(). You provide options to the javascript call to tinyMCE.init() as a PHP array.
Controller Class:
<?php<?php
// An example of adding the TinyMce helper in app_controller.php.
class AppController extends Controller {
var $helper=array('Javascript','Html','Form','TinyMCE' /*...etc...*/);
}
?>
?>
From somewhere in the view with the textareas:
View Template:
<?php
// Example from a view calling TinyMceHelper::init().
echo $tinyMce->init(array('mode'=>'textareas'));
?>
<?php
// Example from a view calling TinyMceHelper::init().
echo $tinyMce->init(array(
'mode'=>'textareas',
'theme'=>'spaceballs',
'convert_urls'=>false,
)
);
?>
Here is the actual helper.
Helper Class:
<?php<?php
/***********************************************************************
*
* Quick TinyMCE Helper for CakePHP
* Author: C.James Callaway (http://www.cybergod.net) - 08/04/2008
*/
class TinyMceHelper extends HtmlHelper {
var $helpers=array('Javascript');
var $defaults=array(
'theme'=>'simple',
'mode'=>'textareas',
'convert_urls'=>false,
);
function beforeRender(){
$view = ClassRegistry::getObject('view');
if (is_object($view)) {
$view->addScript($this->Javascript->link('tiny_mce/tiny_mce'));
}
}
function init($options=false){
if(!$options){
$options=$this->defaults;
}
$code='tinyMCE.init('.json_encode($options).');';
return $this->Javascript->codeBlock($code);
}
}
?>
Question
20 Multiple Instances in Same page
[I need for editing 2 languages] Thanks
Question
21 Multiple Instances in Same page
How can I get multiple istances of TinyMCE in the same page?
[I need for editing 2 languages] Thanks
Comment
22 RE: Multiple Instances in Same page
Andrea,
That is addressed in the TinyMCE documentation. I haven't used that feature for any production work yet, but from what I remember it should be fairly straightforward. I think you tell TinyMCE to apply itself to all textareas with a specific class.