Agregar patrones de texto personalizados en el editor visual de WP 4.5

25

4.5 ya está disponible y con el nuevo Text Patterns . Me gustaría saber cómo agregar mis propios patrones personalizados.

Echando un vistazo a wp-includes/js/tinymce/plugins/wptextpattern/plugin.js parece bastante sencillo.

var spacePatterns = [
    { regExp: /^[*-]\s/, cmd: 'InsertUnorderedList' },
    { regExp: /^1[.)]\s/, cmd: 'InsertOrderedList' }
];

var enterPatterns = [
    { start: '##', format: 'h2' },
    { start: '###', format: 'h3' },
    { start: '####', format: 'h4' },
    { start: '#####', format: 'h5' },
    { start: '######', format: 'h6' },
    { start: '>', format: 'blockquote' },
    { regExp: /^(-){3,}$/, element: 'hr' }
];

var inlinePatterns = [
    { start: ''', end: ''', format: 'code' }
];

El 33300.6.patch parece ideal:

add_filter( 'tiny_mce_before_init', 'textpatterns_test' );
function textpatterns_test( $init ) {
    $init['wptextpattern_inline_patterns'] = '{
        strong: { start: "*", end: "*", format: "bold" },
        strong2: { start: "**", end: "**", format: "bold" },
        em: { start: "_", end: "_", format: "italic" }
    }';

    return $init;
}

Lamentablemente, por lo que puedo decir, estos patrones no se pueden conectar y ese parche nunca llegó a la versión 4.5.

Entonces, en este punto, tal vez la mejor solución sea duplicar este complemento, eliminar los patrones existentes (para no duplicar patrones) y agregar patrones personalizados. Si ese es el caso, ¿cuál es la mejor práctica para agregar complementos de tinymce en el orden correcto para agregar esta nueva funcionalidad?

¿O hay otra solución menos obvia?

    
pregunta jgraup 14.04.2016 - 15:32

1 respuesta

18

Aquí hay una forma de probar el parche principal # 33300.6 por Annew Ozz , a través de un complemento de prueba en WP 4.5.2, para probar el filtro de patrón de texto.

Demo

Aquí hay un ejemplo de tachado usando ~

$init['wpsetextpattern_inline_patterns'] = '{
    strong:         { start: "*",   end: "*",   format: "bold"          },
    strong2:        { start: "**",  end: "**",  format: "bold"          },
    em:             { start: "_",   end: "_",   format: "italic"        },
    strikethrough:  { start: "~",   end: "~",   format: "strikethrough" }
}';

en el complemento de prueba. Funciona así:

Complementodeprueba

Laestructuradelcomplementodepruebaes:

/plugins/custom-text-patterns/custom-text-patterns.phpjs/plugin.js

dondeestánlosarchivos:

custom-text-patterns.php:

<?php/***PluginName:CustomTextPatternsforWordPress4.5*Description:Tryingoutthecorepatch#33300.6byazaozz,totesttextpatternfiltering.*Version:1.0.0*//***Removethecurrentwptextpatternplugin*/add_filter('tiny_mce_plugins',function($plugins){$key=array_search('wptextpattern',$plugins);if(false!==$key)unset($plugins[$key]);return$plugins;});/***Registerpatch#33300.6asanexternalTinyMCEplugin*/add_filter('mce_external_plugins',function($plugins){$plugins['wpsetextpattern']=plugin_dir_url(__FILE__).'js/plugin.js';return$plugins;});/***Customtextpatterns*/add_filter('tiny_mce_before_init',function($init){$init['wpsetextpattern_inline_patterns']='{strong:{start:"*",  end: "*",  format: "bold" },
        strong2: { start: "**", end: "**", format: "bold" },
        em:      { start: "_",  end: "_",  format: "italic" },
        strikethrough: { start: "~", end: "~", format: "strikethrough" }
    }';

    $init['wpsetextpattern_enter_patterns'] = '{
        h2:         { start: "##", format: "h2" },
        h3:         { start: "###", format: "h3" },
        h4:         { start: "####", format: "h4" },
        h5:         { start: "#####", format: "h5" },
        h6:         { start: "######", format: "h6" },
        blockquote: { start: ">", format: "blockquote" },
        hr:         { regExp: /^(-){3,}$/, element: "hr" }      
    }';

    $init['wpsetextpattern_space_patterns'] = '{
        ul: { regExp: /^[*-]\s/, cmd: "InsertUnorderedList" },
        ol: { regExp: /^1[.)]\s/, cmd: "InsertOrderedList" }
    }';

    return $init;
} );

plugin.js: fusionado con el parche # 33300.6 , reemplazando wptextpattern con wpsetextpattern :

/**
 * Text pattern plugin for TinyMCE
 *
 * @since 4.3.0
 *
 * This plugin can automatically format text patterns as you type. It includes two patterns:
 *  - Unordered list ('* ' and '- ').
 *  - Ordered list ('1. ' and '1) ').
 *
 * If the transformation in unwanted, the user can undo the change by pressing backspace,
 * using the undo shortcut, or the undo button in the toolbar.
 */
( function( tinymce, setTimeout ) {
    if ( tinymce.Env.ie && tinymce.Env.ie < 9 ) {
        return;
    }

    tinymce.PluginManager.add( 'wpsetextpattern', function( editor ) {
        var VK = tinymce.util.VK,
            settings = editor.settings,
            extend = tinymce.extend,
            each = tinymce.each,
            chars = [],
            canUndo;

        /**
         * Setting for the patterns can be added or replaced by using the
         * 'tiny_mce_before_init' filter (from PHP).
         *
         * The editor options are: wptextpattern_space_patterns,
         * wptextpattern_enter_patterns, and wptextpattern_inline_patterns.
         * The format is same as below: an object of objects containing the pattrern settings.
         *
         * Note: the keys in the settings objects are not signigicant. They can be used
         * to override the default settings if needed.
         *
         * Example:
         *     add_filter( 'tiny_mce_before_init', 'textpatterns_test' );
         *     function textpatterns_test( $init ) {
         *         $init['wptextpattern_inline_patterns'] = '{
         *             strong: { start: "*", end: "*", format: "bold" },
         *             strong2: { start: "**", end: "**", format: "bold" },
         *             em: { start: "_", end: "_", format: "italic" }
         *         }';
         *
         *         return $init;
         *     }
         */
        var spacePatterns = extend( {
                ul: { regExp: /^[*-]\s/, cmd: 'InsertUnorderedList' },
                ol: { regExp: /^1[.)]\s/, cmd: 'InsertOrderedList' }
            },
            settings.wpsetextpattern_space_patterns || {}
        );

        var enterPatterns = extend( {
                h2:         { start: '##', format: 'h2' },
                h3:         { start: '###', format: 'h3' },
                h4:         { start: '####', format: 'h4' },
                h5:         { start: '#####', format: 'h5' },
                h6:         { start: '######', format: 'h6' },
                blockquote: { start: '>', format: 'blockquote' },
                hr:         { regExp: /^(-){3,}$/, element: 'hr' }
            },
            settings.wpsetextpattern_enter_patterns || {}
        );

        var inlinePatterns = extend( {
                code: { start: ''', end: ''', format: 'code' }
            },
            settings.wpsetextpattern_inline_patterns || {}
        );

        // Convert to array and sort descending by start length.
        function toSortedArray( patterns ) {
            patterns = tinymce.map( patterns, function( pattern ) {
                return pattern;
            } );

            patterns.sort( function( a, b ) {
                if ( a.start && b.start ) {
                    if ( a.start.length > b.start.length ) {
                        return -1;
                    }

                    if ( a.start.length < b.start.length ) {
                        return 1;
                    }
                }

                return 0;
            });

            return patterns;
        }

        spacePatterns = toSortedArray( spacePatterns );
        enterPatterns = toSortedArray( enterPatterns );
        inlinePatterns = toSortedArray( inlinePatterns );

        each( inlinePatterns, function( pattern ) {
            each( ( pattern.start + pattern.end ).split( '' ), function( c ) {
                if ( tinymce.inArray( chars, c ) === -1 ) {
                    chars.push( c );
                }
            } );
        } );

        editor.on( 'selectionchange', function() {
            canUndo = null;
        } );

        editor.on( 'keydown', function( event ) {
            if ( ( canUndo && event.keyCode === 27 /* ESCAPE */ ) || ( canUndo === 'space' && event.keyCode === VK.BACKSPACE ) ) {
                editor.undoManager.undo();
                event.preventDefault();
                event.stopImmediatePropagation();
            }

            if ( event.keyCode === VK.ENTER && ! VK.modifierPressed( event ) ) {
                enter();
            }
        }, true );

        editor.on( 'keyup', function( event ) {
            if ( event.keyCode === VK.SPACEBAR && ! event.ctrlKey && ! event.metaKey && ! event.altKey ) {
                space();
            } else if ( event.keyCode > 47 && ! ( event.keyCode >= 91 && event.keyCode <= 93 ) ) {
                inline();
            }
        } );

        function inline() {
            var rng = editor.selection.getRng();
            var node = rng.startContainer;
            var offset = rng.startOffset;
            var startOffset;
            var endOffset;
            var pattern;
            var format;
            var zero;

            if ( ! node || node.nodeType !== 3 || ! node.data.length || ! offset ) {
                return;
            }

            if ( tinymce.inArray( chars, node.data.charAt( offset - 1 ) ) === -1 ) {
                return;
            }

            function findStart( node ) {
                var offset;

                each( inlinePatterns, function( currentPattern ) {
                    pattern = currentPattern;
                    offset = node.data.indexOf( pattern.end );

                    if ( offset !== -1 ) {
                        return false;
                    }
                } );

                return offset;
            }

            startOffset = findStart( node );
            endOffset = node.data.lastIndexOf( pattern.end );

            if ( startOffset === endOffset || endOffset === -1 ) {
                return;
            }

            if ( endOffset - startOffset <= pattern.start.length ) {
                return;
            }

            if ( node.data.slice( startOffset + pattern.start.length, endOffset ).indexOf( pattern.start.slice( 0, 1 ) ) !== -1 ) {
                return;
            }

            format = editor.formatter.get( pattern.format );

            if ( format && format[0].inline ) {
                editor.undoManager.add();

                editor.undoManager.transact( function() {
                    node.insertData( offset, '\u200b' );

                    node = node.splitText( startOffset );
                    zero = node.splitText( offset - startOffset );

                    node.deleteData( 0, pattern.start.length );
                    node.deleteData( node.data.length - pattern.end.length, pattern.end.length );

                    editor.formatter.apply( pattern.format, {}, node );

                    editor.selection.setCursorLocation( zero, 1 );
                } );

                // We need to wait for native events to be triggered.
                setTimeout( function() {
                    canUndo = 'space';

                    editor.once( 'selectionchange', function() {
                        var offset;

                        if ( zero ) {
                            offset = zero.data.indexOf( '\u200b' );

                            if ( offset !== -1 ) {
                                zero.deleteData( offset, offset + 1 );
                            }
                        }
                    } );
                } );
            }
        }

        function firstTextNode( node ) {
            var parent = editor.dom.getParent( node, 'p' ),
                child;

            if ( ! parent ) {
                return;
            }

            while ( child = parent.firstChild ) {
                if ( child.nodeType !== 3 ) {
                    parent = child;
                } else {
                    break;
                }
            }

            if ( ! child ) {
                return;
            }

            if ( ! child.data ) {
                if ( child.nextSibling && child.nextSibling.nodeType === 3 ) {
                    child = child.nextSibling;
                } else {
                    child = null;
                }
            }

            return child;
        }

        function space() {
            var rng = editor.selection.getRng(),
                node = rng.startContainer,
                parent,
                text;

            if ( ! node || firstTextNode( node ) !== node ) {
                return;
            }

            parent = node.parentNode;
            text = node.data;

            each( spacePatterns, function( pattern ) {
                var match = text.match( pattern.regExp );

                if ( ! match || rng.startOffset !== match[0].length ) {
                    return;
                }

                editor.undoManager.add();

                editor.undoManager.transact( function() {
                    node.deleteData( 0, match[0].length );

                    if ( ! parent.innerHTML ) {
                        parent.appendChild( document.createElement( 'br' ) );
                    }

                    editor.selection.setCursorLocation( parent );
                    editor.execCommand( pattern.cmd );
                } );

                // We need to wait for native events to be triggered.
                setTimeout( function() {
                    canUndo = 'space';
                } );

                return false;
            } );
        }

        function enter() {
            var rng = editor.selection.getRng(),
                start = rng.startContainer,
                node = firstTextNode( start ),
                text, pattern, parent;

            if ( ! node ) {
                return;
            }

            text = node.data;

            each( enterPatterns, function( currentPattern ) {
                if ( currentPattern.start ) {
                    if ( text.indexOf( currentPattern.start ) === 0 ) {
                        pattern = currentPattern;
                        return false;
                    }
                } else if ( currentPattern.regExp ) {
                    if ( currentPattern.regExp.test( text ) ) {
                        pattern = currentPattern;
                        return false;
                    }
                }
            } );

            if ( ! pattern ) {
                return;
            }

            if ( node === start && tinymce.trim( text ) === pattern.start ) {
                return;
            }

            editor.once( 'keyup', function() {
                editor.undoManager.add();

                editor.undoManager.transact( function() {
                    if ( pattern.format ) {
                        editor.formatter.apply( pattern.format, {}, node );
                        node.replaceData( 0, node.data.length, ltrim( node.data.slice( pattern.start.length ) ) );
                    } else if ( pattern.element ) {
                        parent = node.parentNode && node.parentNode.parentNode;

                        if ( parent ) {
                            parent.replaceChild( document.createElement( pattern.element ), node.parentNode );
                        }
                    }
                } );

                // We need to wait for native events to be triggered.
                setTimeout( function() {
                    canUndo = 'enter';
                } );
            } );
        }

        function ltrim( text ) {
            return text ? text.replace( /^\s+/, '' ) : '';
        }
    } );
} )( window.tinymce, window.setTimeout );
    
respondido por el birgire 09.05.2016 - 13:06

Lea otras preguntas en las etiquetas