The perils of Redactor button initialization in JS


$(document).on('EditorInit', function (event, ed) {
   // redactor === undefined
   var redactor = ed.$'redactor');

   setTimeout(function () {
     // redactor instance is finally here
     redactor = ed.$'redactor');
     console.debug('redactor instance');

     // looks like it is a good place to change instance behaviour
     redactor.buildDropdown = function () {
       // bad place, affects only FF!

   window.RedactorPlugins.myPlugin = {
     init: function () {
       // redactor === undefined... but only in GC

       setTimeout(function () {
         // runs ahead of 'redactor instance' in GC and IE... but not in FF!
         console.debug('redactor plugin init');

   ed.config.buttonsCustom.definedButton.callback = function () {
     console.debug('defined button callback');

   setTimeout(function () {
     // asynchronously defined callback... does not affect GC!
     ed.config.buttonsCustom.anotherDefinedButton.callback = function () {
       console.debug('another defined button callback');
   }, 50);

I'm not quite sure that the code is workable, but it should give an idea, I've tried to get the gist from my source.

I've got several cross-browser troubles here:
  • I cannot get Redactor instance from textarea right on EditorInit, it is there only after timeout
  • I cannot get Redactor instance in plugin init, it is there only after timeout - in Chrome
  • Redactor plugins are initialized before I've got a chance to put my hands on Redactor instance - in Chrome and IE11
  • I cannot change buttonsCustom callback (and possibly other button props) after plugin init - in Chrome
What causes these issues? Is there possibility that all of these problems can be overcome?

Are these kinks caused by Xenforo or Redactor client-side scripts? I've dug through redactor.js, xenforo.js and bb_code_edit.js but got no clues what could abuse trouble-free (relatively) browsers so badly.

@cclaerhout nailed it nicely in BBM:
            if(typeof self._init !== undefined){
                self.exec(self); //FF loader (the plugin is loader after the init)

            $(document).on('bbmButtonsPlugin', function(){
                self.exec(self); //Chrome loader - (the plugin is loaded before the init)

I think this part of XF deserves some explanation.
Last edited:
Top Bottom