Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TinyMCE 4.0+ Custom Button active and Inactive when clicking 'Custom Formatted' text

I added a custom button/plugin to tinyMCE 4.0+ which formatBlocked my text with a specific tag. For example: <h1>my clicked text</h1>. Everything worked great except for the fact that the button would not activate. And when it did activate, it wouldn't activate when I clicked on the text that was already formatted, (like the Bold button does when you click on bolded text).

In thanks to the countless suggestions from Stackoverflow and because of the complete lack of a proper solution (here and on the tinyMCE Documentation) I wanted to post the solution here. Although you can add any tags that you'd like, for the purposes of this example, I'm going to add <h1> tags:

//Add the plugin to tinyMCE.init
tinymce.init({
    selector: \"div.editable\",
    inline: true,
    plugins: 'addh1s'
    toolbar: 'addh1s'
 //etc...
});

//Then create a folder entitled, 'addh1s' in the tinyMCE 'plugins' folder
//and add the plugin.min.js file that contains the following code.
//*Please note that the number '27' below is the number in order of the 
//'addh1s' button on my tinyMCE toolbar.  In your case it can be the
//number of where your button appears on your toolbar.

tinymce.PluginManager.add('addh1s', function(editor, url) {
    editor.addButton('addh1s', {
        title: 'Add H1 tags',
        image: '../images/h1.png',
        onPostRender: function() {
            editor.on('NodeChange', function(e) {
                if (editor.formatter.match('h1')) {
                tinymce.activeEditor.theme.panel.find('toolbar *')[27].active(true);
                }
                else {
                tinymce.activeEditor.theme.panel.find('toolbar *')[27].active(false);
                }
            });
            },
        onclick: function() {
            tinyMCE.activeEditor.execCommand('FormatBlock', false, 'h1');
        }
    });

});

I hope this saves you countless frustrating hours!!!

like image 732
Antonius Avatar asked Oct 27 '14 05:10

Antonius


2 Answers

This is exactly what I was looking for! (however I spent a couple of frustrating hours while trying to get there :P)

Just wanted to note down a more reliable and generic way I found to identify the button, to get rid of the customization for the 28th button.

onPostRender: function() {
    var _this = this;   // reference to the button itself
    editor.on('NodeChange', function(e) {
        _this.active(editor.formatter.match('h1'));
    })
}
like image 195
ilPittiz Avatar answered Nov 15 '22 12:11

ilPittiz


I wanted to do this with an element's class, rather than its node type. Here's my solution (uses jQuery, which is included already - this being a Wordpress build )

        ed.addButton('add_top_margin',{
            title : 'Add extra margin to the top of this element',
            text : 'Add Top Margin',
            onclick : function(){
                ed.dom.toggleClass( ed.selection.getNode(), 'top_margin' );
                this.active( !this.active() ); //toggle the button too
            },
            onPostRender: function() {
                var _this = this;   // reference to the button itself
                ed.on('NodeChange', function(e) {
                    //activate the button if this parent has this class
                    var is_active = jQuery( ed.selection.getNode() ).hasClass('top_margin');
                    _this.active( is_active );
                })
            }
        })

and the css:

.top_margin{ 
    margin-top: 1rem;
}
like image 22
Mike Skinner Avatar answered Nov 15 '22 13:11

Mike Skinner