TinyMCE adding toggle style

In case someone doesn't want to do it the 'plug-in' way, here's the guide for TinyMCE 4.x.

First of all, you need to define a custom format:

formats: {
   custom_format: {inline: 'span', styles: {color: "red"}, attributes: {class: 'some_css_class'}}
}

Then you'll have to add a button to your toolbar:

toolbar: "mybutton",

Next, you need to setup your button, so that it toggles the format:

setup: function(editor) {
        editor.addButton('mybutton', {
            text: 'My button',
            icon: false,
            onclick: function() {
                tinymce.activeEditor.formatter.toggle('custom_format')
            }
        });
}

Furthermore, if you want the editor to set the state of the button to indicate the format of current node, automatically, add this to setup function:

onPostRender: function() {
    var ctrl = this;                
    editor.on('NodeChange', function(e) {
        ctrl.active(e.element.className == "some_css_class")
    });
}

Your tinymce.init function should look like this:

tinymce.init({
    selector: "textarea",
    formats: {
       // Other formats...
       custom_format: {inline: 'span', styles: {color: "red"}, attributes: {class: 'some_css_class'}}
    }
    // Other default toolbars
    toolbar_n: "mybutton",

    // Finally, setup your button
    setup: function(editor) {
        editor.addButton('mybutton', {
            text: 'My Button',
            icon: false,
            onclick: function() {
                tinymce.activeEditor.formatter.toggle('custom_format')
            },
            onPostRender: function() {
                var ctrl = this;                
                editor.on('NodeChange', function(e) {
                    ctrl.active(e.element.className == "some_css_class")
                });
            }
        });
    }

Note that class attribute I added to my custom format. This approach made it possible for me define my custom styles in a separate stylesheet file and keep my markup as dry as possible (No inline styling!). Point content_css option to your stylesheet and you'll be good to go. However, due to fact that I'm using Rails as back-end and BatmanJS as front-end (and I'm fairly new to the latter), I couldn't figure out how assets routing works, and ended up adding my custom styles to default content stylesheet file of tinyMCE skin itself (located at skins/SKIN_NAME/content.min.css).


Thanks to Thariama for insights that allowed me to dig deeper finally figuring out how to do this. I'm not sure its the "right way" but as I said TinyMCE has the worst documentation imaginable.

The key for me was to make an hook the onNodeChange event, using the setActive trick. Full example plugin with a custom button that activates when that format is present wherever the cursor is:

(function() {
   tinymce.create('tinymce.plugins.CoolPlugin', {  
   init : function(ed, url) {   

      ed.addCommand('MyFormat', function(ui, v) {
        ed.formatter.toggle("myFormat");
      });

      ed.addButton("coolformat", {
        title : 'MyFormat Tooltip', 
        cmd : 'MyFormat',
        image: url + '/coolformat.png',
      });

      ed.onNodeChange.add(function(ed, cm, n) {
        active = ed.formatter.match('myFormat');
        control = ed.controlManager.get('coolformat').setActive(active);
      });

      ed.onInit.add(function(ed, e) {
        ed.formatter.register('myFormat', 
           {inline: 'span', classes : ['cool'] } );
      });
  }
  });

  // Register plugin
  tinymce.PluginManager.add('cool', tinymce.plugins.CoolPlugin);
})();