Log in or register to post comments
Last post
hikari's picture
Joined: 27/09/2009
Posts: 10
CKEditor For WordPress not working for comments
Hello guys.

I'm trying to use CKEditor For WordPress (http://wordpress.org/extend/plugins/cke ... wordpress/) to add a WYSIWYG to comments form, but it's not working. The original textarea is hidden, but no editor is added in pace of it.



I downloaded the full package and set _source to be used, then I tried to figure out what's wrong.

In the file \ckeditor-for-wordpress\includes\ckeditor.utils.js, I saw that the function ckeditorOn() is being called, and inside it the following code is run:
CKEDITOR.replace(ckeditorSettings.textarea_id, ckeditorSettings.configuration);


CKEDITOR.replace() is defined in \ckeditor\_source\core\ckeditor_basic.js, and simply calls the function createInstance(), which loads CKEditor core and then calls CKEDITOR.editor.replace() (in editor_basic.js), which should replace original HTML element by the editor. But it's not working.

CKEDITOR.editor.replace() simply assures the HTML element is an object and not the element's ID, and then instantiates a CKEditor intance passing its config, the element object and setting it to replace the object:
return new CKEDITOR.editor( config, element, CKEDITOR.ELEMENT_MODE_REPLACE );


Still in editor_basic.js, we have a basic implementation of CKEDITOR.editor(), whose _init() function should add the object to an array at CKEDITOR.editor._pending. But this function isn't called (I know it because I added alerts inside the function and they aren't called), instead, the full class defined in editor.js is called 2 times.

Still in editor.js, there's a code that may be related:
CKEDITOR.on( 'loaded', function()
   {
      // Run the full initialization for pending editors.
      var pending = CKEDITOR.editor._pending;
      if ( pending )
      {
         delete CKEDITOR.editor._pending;

         for ( var i = 0 ; i < pending.length ; i++ )
            pending[ i ]._init();
      }
   });


CKEDITOR.editor._pending is looped and all objects on it have their _init() function called.

editor.js's CKEDITOR.editor.prototype._init() seems to load the editor, and first time it runs it goes to its end and returns, but the replacement isn't done. Second time it runs, it sees that the element name (this.name) is already in CKEDITOR.instances, and then throws an exception and halts.

I removed the exception throwing and then the code continues normally, but it again returns without replacing the textarea element with the editor.

I'm in a dead end now, could somebody help me?
hikari's picture
Joined: 27/09/2009
Posts: 10
Re: CKEditor For WordPress not working for comments
I keep trying to debug. Everything seems to run fine until in editor.js, the following call isn't processed:
CKEDITOR.plugins.load( plugins.split( ',' ), function( plugins )


plugins seems to be fine, it's a string with a bunch of plugins names separated by ','

Just before the call I use alert() to see what's inside plugins, but then nothing else happens.

As I can understand, this function should be called so that loadTheme() is called inside it. loadTheme() would call editorTheme.build(), that's defined in theme.js, and would build editor's HTML, store it in the variable "container", and then insert it to DOM.

So, why aren't plugins finishing to be loaded?
hikari's picture
Joined: 27/09/2009
Posts: 10
Re: CKEditor For WordPress not working for comments
Ok, I discovered what was breaking it.

I suspected the problem was not in the editor itself because it's tested in many platforms, while plugin files are still beta and less used, but I couldn't find it.


editor.config.extraPlugins has a bunch of plugins that aren't working. They don't seem to be added directly by the plugin, I couldn't find where they are coming from, but I found where they are being added.

In \ckeditor\_source\core\config.js, CKEDITOR.config.plugins defines these default plugins:
'about,a11yhelp,basicstyles,blockquote,button,clipboard,colorbutton,colordialog,contextmenu,div,elementspath,enterkey,entities,filebrowser,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,maximize,newpage,pagebreak,pastefromword,pastetext,popup,preview,print,removeformat,resize,save,scayt,smiley,showblocks,showborders,sourcearea,stylescombo,table,tabletools,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc'


but editor.config.extraPlugins had these:
"about,a11yhelp,basicstyles,blockquote,button,clipboard,colorbutton,colordialog,contextmenu,div,elementspath,enterkey,entities,filebrowser,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,maximize,newpage,pagebreak,pastefromword,pastetext,popup,preview,print,removeformat,resize,save,scayt,smiley,showblocks,showborders,sourcearea,stylescombo,table,tabletools,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc,eachSlice,all,any,collect,detect,findAll,grep,include,inGroupsOf,inject,invoke,max,min,partition,pluck,reject,sortBy,toArray,zip,size,inspect,find,select,member,entries,_reverse,_each,clear,first,last,compact,flatten,without,uniq,intersect,clone,toJSON"


Wherever they are coming from, they are added in \ckeditor-for-wordpress\includes\ckeditor.utils.js, so we just need to comment the line that adds them to the editor:
//evt.editor.config.extraPlugins += (evt.editor.config.extraPlugins ? ','+externals.join(',') : externals.join(','));


Commenting this line they stop being added. But there's still another plugin bugging, "find", so we also must remove it.

Still inside the "configLoaded" event listener, we add the folloing code:
   ckeditorSettings.configuration['on'] = {
      configLoaded : function ( evt ) {

// (...)

         var remove = "find";
         evt.editor.config.removePlugins += (evt.editor.config.removePlugins ? ','+remove : remove);
      }
   }


Using "removePlugins" property, all plugins listed there will be removed when plugins are loaded, and finally doing that the editor will load!


But there are still 2 other bugs. The plugin offers 3 toolbars: WordpressBasic, WordpressFull and Full, but Full is not working. I set it to use WordpressFull and worked fine.

Also, when reply is used and comment form is moved, the editor brokes. comment-reply.js must be hacked to remove the editor before the move, then brought back after it. There's a TinyMCE plugin that implements it, and CKEditor plugin has functions to "easily" load and unload the editor, so it must be easy to adapt.
wiktor's picture
Joined: 16/07/2007
Posts: 1645
Re: CKEditor For WordPress not working for comments
Hi Hikari,

Are you experiencing this bug in fresh install of WordPress?

those "extra plugins":
eachSlice,all,any,collect,detect,findAll,grep,include,inGroupsOf,inject,invoke,max,min,partition,pluck,reject,sortBy,toArray,zip,size,inspect,find,select,member,entries,_reverse,_each,clear,first,last,compact,flatten,without,uniq,intersect,clone,toJSON

are taken from prototype.js that is included in the "redirection" plugin for example... try disabling other plugins to see where is it coming from.

Wiktor Walc
CTO, CKSource - http://cksource.com
--
Follow CKEditor on: Twitter | Facebook | Google+

hikari's picture
Joined: 27/09/2009
Posts: 10
Re: CKEditor For WordPress not working for comments
ok tnx :)

but it comes directly from prototype.js or could it be a Wordpress plugin doing it?

because it will be hard to take prototype out or stop using a plugin because of a conflict. It's better to prevent the conflict from happening :)

I'll make some tests and reply later
wiktor's picture
Joined: 16/07/2007
Posts: 1645
Re: CKEditor For WordPress not working for comments
Well perhaps my reply wasn't clear - we just need to find out which plugin is causing this bug, because I don't have it on a vanilla installation of WordPress.
Perhaps it's "redirection" if you're using it, if not, let's check the other plugins.

Wiktor Walc
CTO, CKSource - http://cksource.com
--
Follow CKEditor on: Twitter | Facebook | Google+

hikari's picture
Joined: 27/09/2009
Posts: 10
Re: CKEditor For WordPress not working for comments
sorry for the delay


ok, I found it

Collapsing Archives plugin enqueues "scriptaculous-effects" js, which enqueues scriptaculous, which enqueues prototype

I disabled Collapsing Archives and now CKEditor works!

I also found another bug, if I use krumo in a page, CKEditor loads, but I can't type text inside it. It doesn't get focus at all. krumo is just a debug feature and should never be used in production sites, but I'm just reporting the bug, and also I fear other plugins adding JS that may conflict with CKEditor, even more if prototype can't be used with it.

If it's only those JS plugins coming from prototype that are conflicting, it's a good idea to implement my suggestion and add them to editor.config.removePlugins, so that those strings are removed when loading CKEditor and it works together with prototype.



Now, there's also the comment-reply.js conflict. Everytime somebody tries to reply a comment, the whole comment form is moved in DOM, and CKEditor breaks. Since you already have 2 simple functions to load and unload the editor, it's just a matter of calling them everytime comment_reply runs.

http://wordpress.org/extend/plugins/tinymcecomments/ already did that, he hacked comment-reply.js and added his own. If you want I can port his file to support CKEditor, then you do as he did and replace the original.

I'm gonna try it, later I say how it goes.
hikari's picture
Joined: 27/09/2009
Posts: 10
Re: CKEditor For WordPress not working for comments
It did it! it was much easier than I thought!!

I'll publish the code here for now and do some more tests, if anything new shows up I update it.

original \wp-includes\js\comment-reply.dev.js :
addComment = {
   moveForm : function(commId, parentId, respondId, postId) {
      var t = this, div, comm = t.I(commId), respond = t.I(respondId), cancel = t.I('cancel-comment-reply-link'), parent = t.I('comment_parent'), post = t.I('comment_post_ID');

      if ( ! comm || ! respond || ! cancel || ! parent )
         return;

      t.respondId = respondId;
      postId = postId || false;

      if ( ! t.I('wp-temp-form-div') ) {
         div = document.createElement('div');
         div.id = 'wp-temp-form-div';
         div.style.display = 'none';
         respond.parentNode.insertBefore(div, respond);
      }

      comm.parentNode.insertBefore(respond, comm.nextSibling);
      if ( post && postId )
         post.value = postId;
      parent.value = parentId;
      cancel.style.display = '';

      cancel.onclick = function() {
         var t = addComment, temp = t.I('wp-temp-form-div'), respond = t.I(t.respondId);

         if ( ! temp || ! respond )
            return;

         t.I('comment_parent').value = '0';
         temp.parentNode.insertBefore(respond, temp);
         temp.parentNode.removeChild(temp);
         this.style.display = 'none';
         this.onclick = null;
         return false;
      }

      try { t.I('comment').focus(); }
      catch(e) {}

      return false;
   },

   I : function(e) {
      return document.getElementById(e);
   }
}


updated to support CKEditor:
addComment = {
   moveForm : function(commId, parentId, respondId, postId) {
      var t = this, div, comm = t.I(commId), respond = t.I(respondId), cancel = t.I('cancel-comment-reply-link'), parent = t.I('comment_parent'), post = t.I('comment_post_ID');

      if ( ! comm || ! respond || ! cancel || ! parent )
         return;
ckeditorOff();
      t.respondId = respondId;
      postId = postId || false;

      if ( ! t.I('wp-temp-form-div') ) {
         div = document.createElement('div');
         div.id = 'wp-temp-form-div';
         div.style.display = 'none';
         respond.parentNode.insertBefore(div, respond);
      }

      comm.parentNode.insertBefore(respond, comm.nextSibling);
      if ( post && postId )
         t.I('comment_post_ID').value = postId;
      t.I('comment_parent').value = parentId;
      cancel.style.display = '';

      cancel.onclick = function() {
         var t = addComment, temp = t.I('wp-temp-form-div'), respond = t.I(t.respondId);

         if ( ! temp || ! respond )
            return;
ckeditorOff();
         t.I('comment_parent').value = '0';
         temp.parentNode.insertBefore(respond, temp);
         temp.parentNode.removeChild(temp);
         this.style.display = 'none';
         this.onclick = null;
ckeditorOn();
         return false;
      }
ckeditorOn()
      try { t.I('comment').focus(); }
      catch(e) {}

      return false;
   },

   I : function(e) {
      return document.getElementById(e);
   }
}


Use this code in a file in ur plugin root folder named comment-reply.js, then add the following code inside ckeditor_wordpress.add_comment_js():

      wp_deregister_script('comment-reply');
      wp_register_script( 'comment-reply', plugin_dir_url(__FILE__). "comment-reply.js", array('ckeditor.utils'), '20090102');


In a few tests it worked great, I can move comment form around and CKEditor continues working.
hikari's picture
Joined: 27/09/2009
Posts: 10
Re: CKEditor For WordPress not working for comments
Only problem I've seen is that editor becomes unable to be focuses sometimes. When I change FireFox tab or open FireBug that happens. To fix it I must click Source to take editor off and click again to bring back.

In case you wanna see my environment, it's being used in http://Hikari.ws
hikari's picture
Joined: 27/09/2009
Posts: 10
Re: CKEditor For WordPress not working for comments
Another bug found. In ckeditor_wordpress.php you set $ckeditor_wordpress->add_comment_js() to be executed on 'wp_print_scripts' action.

But inside that function you call add_wpcompat_styles(), which prints some styles... in footer! It makes HTML invalid.

A quick and durty solution for that is remove add_wpcompat_styles() call from add_comment_js() and hook it to 'wp_head'.

But you are hooking everything at once needlessly: admin hooks don't need to be hooked in frontend, and CKEditor for comments is only needed in single pages (is_singular() true), and also these hooks should only be called during 'init' action instead of during plugins loading.

I'm gonna take a deeper look on each of them and later I'll provide a complete code to them all.



Another note, I've been using CKEditor in my production site and received a few comments whose commentators used it :D