Limit the number of character in tinyMCE Limit the number of character in tinyMCE javascript javascript

Limit the number of character in tinyMCE


This works in tinyMCE 4.3.12 and also captures pasting:

EDIT: Fixed bugs and extended code to display a character counter under the editor. Possibly not the best way as it relies a bit on the current HTML structure of tinyMCE having the editor div before the hidden textarea.

This version only counts the text length and ignores HTML tag length. To count full HTML length, replace all "innerText" with "innerHTML".

tinymce.init({    max_chars: 1000, // max. allowed chars    setup: function (ed) {        var allowedKeys = [8, 37, 38, 39, 40, 46]; // backspace, delete and cursor keys        ed.on('keydown', function (e) {            if (allowedKeys.indexOf(e.keyCode) != -1) return true;            if (tinymce_getContentLength() + 1 > this.settings.max_chars) {                e.preventDefault();                e.stopPropagation();                return false;            }            return true;        });        ed.on('keyup', function (e) {            tinymce_updateCharCounter(this, tinymce_getContentLength());        });    },    init_instance_callback: function () { // initialize counter div        $('#' + this.id).prev().append('<div class="char_count" style="text-align:right"></div>');        tinymce_updateCharCounter(this, tinymce_getContentLength());    },    paste_preprocess: function (plugin, args) {        var editor = tinymce.get(tinymce.activeEditor.id);        var len = editor.contentDocument.body.innerText.length;        var text = $(args.content).text();        if (len + text.length > editor.settings.max_chars) {            alert('Pasting this exceeds the maximum allowed number of ' + editor.settings.max_chars + ' characters.');            args.content = '';        } else {            tinymce_updateCharCounter(editor, len + text.length);        }    }});function tinymce_updateCharCounter(el, len) {    $('#' + el.id).prev().find('.char_count').text(len + '/' + el.settings.max_chars);}function tinymce_getContentLength() {    return tinymce.get(tinymce.activeEditor.id).contentDocument.body.innerText.length;}

Reference: How can I prevent tinyMCE's paste event?


TinyMCE 4+
+
jQuery

<textarea id="description_edit" name="description_edit"><?=htmlspecialchars($this->company->description);?></textarea><div><span>Characters left:</span> <span id="chars_left"></span></div><script type="text/javascript" src="/js/tinymce/tinymce.min.js"></script><script>    var max_chars = 200; //max characters    var max_for_html = 300; //max characters for html tags    var allowed_keys = [8, 13, 16, 17, 18, 20, 33, 34, 35, 36, 37, 38, 39, 40, 46];    var chars_without_html = 0;    function alarmChars() {        if (chars_without_html > (max_chars - 25)) {            $('#chars_left').css('color', 'red');        } else {            $('#chars_left').css('color', 'gray');        }    }    $(function () {        tinymce.init({            selector: "#description_edit",            theme: "modern",            width: 320,            height: 130,            plugins: [                "advlist autolink lists charmap print preview hr anchor pagebreak",                "searchreplace visualblocks visualchars code insertdatetime media nonbreaking",                "save table contextmenu directionality paste textcolor"            ],            image_advtab: true,            language: 'en',            menubar: false,            statusbar: false,            setup: function (ed) {                ed.on("KeyDown", function (ed, evt) {                    chars_without_html = $.trim(tinyMCE.activeEditor.getContent().replace(/(<([^>]+)>)/ig, "")).length;                    chars_with_html = tinyMCE.activeEditor.getContent().length;                    var key = ed.keyCode;                    $('#chars_left').html(max_chars - chars_without_html);                    if (allowed_keys.indexOf(key) != -1) {                        alarmChars();                        return;                    }                    if (chars_with_html > (max_chars + max_for_html)) {                        ed.stopPropagation();                        ed.preventDefault();                    } else if (chars_without_html > max_chars - 1 && key != 8 && key != 46) {                        alert('Characters limit!');                        ed.stopPropagation();                        ed.preventDefault();                    }                    alarmChars();                });            },            toolbar: "bold italic underline | alignleft aligncenter alignright alignjustify | forecolor backcolor | bullist numlist | charmap",            style_formats: [                {title: 'Bold text', inline: 'b'},                {title: 'Red text', inline: 'span', styles: {color: '#ff0000'}},                {title: 'Red header', block: 'h1', styles: {color: '#ff0000'}},                {title: 'Example 1', inline: 'span', classes: 'example1'},                {title: 'Example 2', inline: 'span', classes: 'example2'},                {title: 'Table styles'},                {title: 'Table row 1', selector: 'tr', classes: 'tablerow1'}            ]        });        chars_without_html = $.trim($("#description_edit").text().replace(/(<([^>]+)>)/ig, "")).length;        $('#chars_left').html(max_chars - chars_without_html);        alarmChars();    });</script>


Answers above were great! I've made a small amendment so that we can set max_chars by adding it as an attribute to textarea element itself

setup : function(ed) {        ed.onKeyDown.add(function(ed, evt) {            //if ( $(ed.getBody()).text().length+1 > ed.getParam('max_chars')){            if ( $(ed.getBody()).text().length+1 > $(tinyMCE.get(tinyMCE.activeEditor.id).getElement()).attr('max_chars')){                evt.preventDefault();                evt.stopPropagation();                return false;            }        });    }