Amleonard Amleonard - 7 months ago 104
Javascript Question

Proper Way Of Modifying Toolbar After Init in TinyMCE

I am extending a cloud-hosted LMS with javascript. Therefore, we can add javascript to the page, but cannot modify the vendor javascript for different components.

The LMS uses tinyMCE frequently. The goal is to add a new button on to the toolbar of each tinyMCE editor.

The problem is that since the tinyMCE modules are initialized in the vendor's untouchable code, we cannot modify the init() call. Therefore, we cannot add any text on to the "toolbar" property of the init() object.

So I accomplished this in a moderately hacky way:

tinyMCE.on('AddEditor', function(e){
e.editor.on('init', function(){
tinyMCE.ui.Factory.create({
type: 'button',
icon: 'icon'
}).on('click', function(){
// button pressing logic
})
.renderTo($(e.editor.editorContainer).find('.mce-container-body .mce-toolbar:last .mce-btn-group > div')[0])
});
});


So this works, but needless to say I am not totally comfortable having to look for such a specific location in the DOM like that to insert the button. Although this works, I do not believe it was the creator's intention for it to be used like this.

Is there a proper way to add the button to a toolbar, after initialization, if we cannot modify the initialization code?

Answer

I found a more elegant solution, but it still feels a bit like a hack. Here is what I got:

// get an instance of the editor
var editor=tinymce.activeEditor; //or tinymce.editors[0], or loop, whatever

//add a button to the editor buttons
editor.addButton('mysecondbutton', {
  text: 'My second button',
  icon: false,
  onclick: function () {
    editor.insertContent('&nbsp;<b>It\'s my second button!</b>&nbsp;');
  }
});

//the button now becomes
var button=editor.buttons['mysecondbutton'];

//find the buttongroup in the toolbar found in the panel of the theme
var bg=editor.theme.panel.find('toolbar buttongroup')[0];

//without this, the buttons look weird after that
bg._lastRepaintRect=bg._layoutRect;

//append the button to the group
bg.append(button);

I feel like there should be something better than this, but I didn't find it.

Other notes:

  • the ugly _lastRepaintRect is needed because of the repaint method, which makes the buttons look ugly regardless if you add new controls or not
  • looked in the code, there is no way of adding new controls to the toolbar without repainting and there is no way to get around it without the ugly hack
  • append(b) is equivalent to add(b).renderNew()
  • you can use the following code to add the button without the hack, but you are shortcircuiting a lot of other stuff:

Code:

bg.add(button);
var buttonElement=bg.items().filter(function(i) { return i.settings.text==button.text; })[0];
var bgElement=bg.getEl('body');
buttonElement.renderTo(bgElement);