1

Tabs placed in a <pre><code></code></pre> block are stripped and line breaks are removed leaving a single continuous line of text. This occurs when switching from html to visual editors. Is there a setting in TinyMCE to avoid this?

BEFORE:

enter image description here

AFTER: enter image description here

Here it even garbles the code and spits parts of it out the <pre>...

EDIT:

I seems the best option is to remove the <code> tag entirely and leave the pre. This still has the issue of removing duplicate blank lines, but it keeps the pre untouched even when switching between editors.

3

Add to function.php

add_filter('tiny_mce_before_init', 'tiny_mce_before_init');

And function tiny_mce_before_init:

function tiny_mce_before_init($init) {
 $init['setup'] = "function(ed) {
     ed.onBeforeSetContent.add(function(ed, o) {
     if ( o.content.indexOf('<pre') != -1) {
     o.content = o.content.replace(/<pre[^>]*>[\\s\\S]+?<\\/pre>/g, function(a) {
     return a.replace(/(\\r\\n|\\n)/g, '<br />');
    });
   }
  });
 }";
 return $init;
}

http://core.trac.wordpress.org/ticket/19666 - it's known bug, there is workaround but not fix tabs only new line chars

  • Fixed in Wordpress 3.5+ – OzzyCzech Feb 13 '13 at 10:44
1

I have also added custom shortcodes to functions.php to avoid things breaking when switching from html to visual editors. Mainly I've used this for iFrame's, but maybe it would be helpful here too.

  • This will help with the iframes: public static function init_tinymce($init) { $init['extended_valid_elements'] .= ',pre[*],code[*],iframe[*]'; return $init; } add_filter('tiny_mce_before_init', 'init_tinymce'); – Aram Kocharyan Mar 20 '12 at 23:07
0

This plugin seems to preserve white space between <pre> tags.

Preserve Code Formatting

0

For anyone who struggles with pasting or working with formatted <pre> code in Visual editor. This solution has been working for me many years, and I love it. This approach uses a "middle-hand" to serve correct pre-content and characters between the editors and wpautop() frontend.

Just paste into functions.php

It seems heavy, but thats why jQuery must be in global scope as it talks with tinMCE API. The dollarsign $ can NOT be in use and the jQuery text clutter the code down. Its mostly the creation of HTML elements that takes space.

How it works: Pretty simple, Without "touching" it -TinyMCE dont mess with it. Its worth trying out!

/**
 * PRE Handler
 * Solves <pre> handle in Wordpress tinyMCE editor
 * TAB support
 * TAB support to TEXT editor
 * Simple cleanup with Undo
 * Push cleanup (experimental)
 * Moves empty code chunks to beginning
**/


function entex_tiny_mce_before_init(){
    add_filter('tiny_mce_before_init', function($mceInit){
        $mceInit['setup'] = 'ua_TinyMCE_setup_callback';
        return $mceInit;
    });
    add_action('before_wp_tiny_mce', 'entex_TinyMCE_javascript');
}
add_action('after_setup_theme', 'entex_tiny_mce_before_init');


function entex_TinyMCE_javascript() {

    echo '<script type="text/javascript">'."\n";
    ?>

    var ua_tinyMCE_invoked = 0;

    function ua_tinyMCE_focusbutton(){
        if(jQuery('ua-id-mce-focusbutton').get(0)) return;
        var jQueryE = jQuery('<a />').addClass('button ua-id-mce-focusbutton').css('float', 'right').on('click', function(){
            jQuery('html, body').stop().animate({ scrollTop: (jQuery('#wp-content-wrap').offset().top) - 20 }, 500);
            tinymce.activeEditor.focus();
            return false;
        }).attr('title', 'Scroll and focus the editor Toolbar in view').text('Toolbar focus').css('margin', '5px');
        jQuery('.mce-statusbar .mce-flow-layout').prepend(jQueryE);
    }

    function ua_TinyMCE_setup_callback(ed){

        if(ua_tinyMCE_invoked) return;
        ua_tinyMCE_invoked = 1;

        ed.on('init', function(e) {
            jQuery(ed.getBody()).on('click', 'pre', function() {
                ua_TinyMCE_edit_pre(ed, this);
                return false;
            });
            ua_tinyMCE_focusbutton();
        });
    }

    function ua_TinyMCE_helper_cleanBeginnings(str, find, replace){
        return str.replace(new RegExp(find, 'g'), replace);
    }

    function ua_TinyMCE_edit_pre(ed, obj) {
        var jQueryE = jQuery(obj); 
        var jQueryB = jQuery(ed.getBody());
        var content = jQuery('<textarea/>').html(jQueryE.html()).text();
        content = content.replace(/(<br>)/g, '');
        //content = content.replace(/   /g, '\t');
        var data = content;


        var jQueryL = jQuery('<div />').css({
            'position': 'fixed',
            'box-sizing': 'border-box',
            'background-color': 'rgba(255, 255, 255, 0.85',
            'border': '3px solid #ccc',
            'padding': '10px',
            'z-index': '9992',
            'height': 'auto',
            'width': '80%',
            'left': '50%',
            'margin-left': '-40%',
            'top': '5%'
        });

        var jQueryT = jQuery('<textarea />').keydown(function(e){

            if ( e.which != 9 ) return;
            var start = this.selectionStart;
            var end = this.selectionEnd;
            this.value = this.value.substr( 0, start ) + "\t" + this.value.substr( end );
            this.selectionStart = this.selectionEnd = start + 1;
            e.preventDefault();
            return false;

        }).attr('wrap', 'soft').css({
            'height': '98%',
            'width': '88%',
            'min-height': '300px',
            'tab-size': '3',
            'font-family': 'courier new',
            'box-sizing': 'border-box'
        });

        jQuery('#wpcontent').css('position', 'relative').append(jQueryL);
        jQueryL.append(jQueryT);
        jQueryL.append(
            jQuery('<div />').css({
                'width': '10%',
                'height': '100%',
                'position': 'absolute',
                'top': '0px',
                'right': '10px',
                'padding-top': '10px',
                'box-sizing': 'border-box'
            }).append(
                jQuery('<a />').attr('title', 'Send to element').click(function(){

                    var encodedStr = jQueryT.val().replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
                        return '&#'+i.charCodeAt(0)+';';
                    });

                    jQueryE.html(encodedStr);
                    ed.focus();
                    jQueryL.remove();
                    return false;

                }).text('Send').addClass('button button-primary').css({
                    'display': 'block',
                    'width': '100%',
                    'margin-bottom': '5px',
                    'text-align': 'center',
                    'box-sizing': 'border-box'
                }), 

                jQuery('<a />').attr('title', 'Cleanup').click(function(){

                    var data = jQueryT.val();
                    var original = data;
                    data = data.replace(/(\r\n|\n|\r)/gm, "\r\n");
                    var workspace = data.replace(/(\r\n|\n|\r)/gm, '');

                    if(/^\s/.test(workspace)) {
                        var search_string = workspace.replace(/^\s+|\s+$/g, '');
                        if(search_string){
                            var firstChar = search_string[0];
                            var remove = workspace.substr(0, workspace.indexOf(firstChar));
                            remove = "\r\n" + remove;
                            data = ua_TinyMCE_helper_cleanBeginnings(data, remove, "\r\n");
                        }
                        data = data.replace(/   /g, "\t");
                        data = data.replace(/^\s+|\s+$/g, '');
                    } else {
                        data = data.replace(/^\s+|\s+$/g, '');
                    }
                    if(data != original){
                        jQueryT.data('original', original);
                        if(!jQuery('#ua-TinyMCE-btt-undo').get(0)){
                        jQuery(this).after(
                            jQuery('<a />').attr('title', 'Undo').click(function(){
                                jQueryT.val(jQueryT.data('original'));
                                jQuery(this).remove();
                                return false;

                            }).text('Undo').addClass('button').css({
                                'display': 'block',
                                'width': '100%',
                                'margin-bottom': '5px',
                                'text-align': 'center',
                                'box-sizing': 'border-box'
                            }).attr('id', 'ua-TinyMCE-btt-undo')
                        );
                        }
                    }
                    data = data.replace(/   /g, "\t");
                    jQueryT.val(data);
                    return false;

                }).text('Cleanup').addClass('button').css({
                    'display': 'block',
                    'width': '100%',
                    'margin-bottom': '5px',
                    'text-align': 'center',
                    'box-sizing': 'border-box'
                }),

                jQuery('<a />').attr('title', 'Close').click(function(){

                    ed.focus();
                    jQueryL.remove();
                    return false;

                }).text('Close').addClass('button').css({
                    'display': 'block',
                    'width': '100%',
                    'margin-bottom': '5px',
                    'text-align': 'center',
                    'box-sizing': 'border-box'
                }),

                jQuery('<a />').attr('title', 'Remove all data').click(function(){

                    jQueryT.val('').focus();
                    return false;

                }).text('Delete').addClass('button').css({
                    'display': 'block',
                    'width': '100%',
                    'margin-bottom': '0px',
                    'position': 'absolute',
                    'bottom': '10px',
                    'background-color': '#D54E21',
                    'color': '#fff',
                    'text-align': 'center',
                    'box-sizing': 'border-box'
                })
            )
        );
        jQueryT.val(content).focus();
        return false;
    }

    // WP EDITOR
    jQuery(document).ready(function($){
        if($('textarea#content').get(0)){
            $('textarea#content').on('keydown', function(e){
                if ( e.which != 9 ) return;
                var start = this.selectionStart;
                var end = this.selectionEnd;
                this.value = this.value.substr( 0, start ) + "\t" + this.value.substr( end );
                this.selectionStart = this.selectionEnd = start + 1;
                e.preventDefault();
                return false;
            }).css('tab-size', '3');
        }
    });

    <?php
    echo '</script>'."\n";
}

This approach is not a hack or a corny preg match solution. It produces the same converastions as default API.

The PUSH cleanup works if you paste a code from a PHP class or whatever and the chunk or cutted out function you wanna present, has a lot of space or tabs "before". It calculates the space that occurs on the first existing line.

Makes this:

                    if(search_string){
                        var firstChar = search_string[0];
                        var remove = workspace.substr(0, workspace.indexOf(firstChar));
                        remove = "\r\n" + remove;
                        data = ua_TinyMCE_helper_cleanBeginnings(data, remove, "\r\n");
                    }

Into This:

if(search_string){
    var firstChar = search_string[0];
    var remove = workspace.substr(0, workspace.indexOf(firstChar));
    remove = "\r\n" + remove;
    data = ua_TinyMCE_helper_cleanBeginnings(data, remove, "\r\n");
}

B.T.W, it comes with a handy focus button, appears at bottom right of editor and is useful when working with large amount of <pre> code chunks. Turn off screen settings "Enable full-height editor and distraction-free functionality." for better UI.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.