TinyMCE custom processing w/ cursor preservation

by Gerald Fullam

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/tinymce/3.5.8/tiny_mce.min.js"></script>
<p>Type -- and watch as it is magically changed to an &mdash; right before your eyes.</p>
<p><em>Bonus: your cursor position is preserved.</em></p>
<form>
    <textarea name="content"></textarea>
</form>

CSS

textarea {
    width: 100%;
    height: 100px;
}

JavaScript

tinymce.init({
    selector: 'textarea',
    language: false, // Prevents language packs from loading
    inline_styles: false, // Don't convert defined styles into inline style attributes
    entity_encoding  : 'named', // Characters will be converted into named entities (ex. &mdash;)
    theme: function (editor, target) {
        var dom = tinymce.DOM,
            editorContainer;

        // Generate UI
        editorContainer = dom.insertAfter(dom.create('div', {
            style: 'border: 1px solid gray'
        },
            '<div>' +
                '<button data-mce-command="bold">B</button>' +
                '<button data-mce-command="italic">I</button>' +
            '</div>' +
            '<div style="border-top: 1px solid gray"></div>'), target);

        // Set editor container size to target element size
        dom.setStyle(editorContainer, 'width', target.offsetWidth);

        // Return editor and iframe containers
        return {
            editorContainer: editorContainer,
            iframeContainer: editorContainer.lastChild,

            // Calculate iframe height: target height - toolbar height
            iframeHeight: target.offsetHeight - editorContainer.firstChild.offsetHeight
        };
    },
    setup: function (editor) {
        var dom = tinymce.DOM, // Object for DOM manipulation and retrival
            bindButtons = function (editor) {
                tinyMCE.each(dom.select('button', editor.editorContainer), function (button) {

                    // Bind events for each button
                    dom.bind(button, 'click', function (e) {
                        e.preventDefault();
                        var cmd = dom.getAttrib(e.target, 'data-mce-command'),
                            val = dom.getAttrib(e.target, 'data-mce-value');

                        // Execute editor command based on data parameters
                        editor.execCommand(cmd, false, val);
                    });

                    //...