it-swarm.com.de

Hinzufügen von benutzerdefinierten Textmustern im WP 4.5 Visueller Editor

4.5 ist raus und damit neu Text Patterns . Ich würde gerne wissen, wie ich meine eigenen benutzerdefinierten Muster hinzufüge.

Ein Blick auf wp-includes/js/tinymce/plugins/wptextpattern/plugin.js scheint ziemlich einfach zu sein.

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' }
];

Der 33300.6.patch sieht ideal aus:

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;
}

Soweit ich weiß, sind diese Patterns leider nicht steckbar, und dieser Patch hat es nie in die Version 4.5 geschafft.

An diesem Punkt ist es vielleicht die beste Lösung, dieses Plugin zu duplizieren, vorhandene Muster zu entfernen (um keine Muster zu duplizieren) und die benutzerdefinierten Muster hinzuzufügen? Wenn dies der Fall ist, was ist die beste Vorgehensweise beim Hinzufügen von Tinymce-Plugins in der richtigen Reihenfolge, um diese neue Funktionalität hinzuzufügen?

Oder gibt es eine andere Lösung, die weniger offensichtlich ist?

25
jgraup

Hier ist eine Möglichkeit, den Core-Patch # 33300.6 von Andew Ozz über ein Test-Plugin in WP 4.5.2 zu testen, um den Textmusterfilter auszuprobieren.

Demo

Hier ist ein durchgestrichen Beispiel mit ~

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

im Test-Plugin. Es funktioniert so:

 strikethrough 

Test Plugin

Die Struktur des Test-Plugins ist:

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

wo die dateien sind:

custom-text-patterns.php:

<?php
/**
 * Plugin Name:     Custom Text Patterns for WordPress 4.5
 * Description:     Trying out the core patch #33300.6 by azaozz, to test textpattern filtering. 
 * Version:         1.0.0
 */

/**
 * Remove the current wptextpattern plugin 
 */ 
add_filter( 'tiny_mce_plugins', function( $plugins )
{
    $key = array_search ( 'wptextpattern', $plugins );
    if( false !== $key )
        unset( $plugins[$key] );

    return $plugins;
} );

/**
 * Register patch #33300.6 as an external TinyMCE plugin
 */ 
add_filter( 'mce_external_plugins', function( $plugins )
{
    $plugins['wpsetextpattern'] = plugin_dir_url( __FILE__ ) . 'js/plugin.js';

    return $plugins;
} );

/**
 * Custom text patterns
 */ 
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: Mit Patch zusammengeführt # 33300.6 , wobei wptextpattern durch wpsetextpattern ersetzt wird:

/**
 * 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 );
18
birgire