Menambahkan Pola Teks Kustom di WP 4.5 Visual Editor

25

4.5 keluar dan dengan itu Pola Teks baru . Saya ingin tahu bagaimana cara menambahkan pola kustom saya sendiri.

Melihat wp-includes/js/tinymce/plugins/wptextpattern/plugin.jsitu tampaknya cukup lurus ke depan.

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

The 33300.6.patchterlihat 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;
}

Sayangnya, dari apa yang bisa saya katakan, pola-pola ini tidak bisa dicolokkan dan tambalan itu tidak pernah berhasil masuk ke rilis 4.5.

Jadi pada titik ini mungkin solusi terbaik adalah dengan menduplikasi plugin ini, menghapus pola yang ada (agar tidak menduplikasi pola) , dan menambahkan pola khusus? Jika itu masalahnya, apa praktik terbaik dalam menambahkan plugin tinymce dalam urutan yang benar untuk menambahkan fungsionalitas baru ini?

Atau adakah solusi lain yang kurang jelas?

jgraup
sumber
2
Tampaknya Anda mungkin kurang beruntung untuk saat ini. Saya tidak dapat melihat kait atau titik masuk, dan membaca lebih lanjut tentang sistem plugin TinyMCE membuatnya tampak seperti tidak ada cara yang baik untuk de-register plugin. Anda mungkin memang harus menulis plugin sendiri tanpa pola teks default dan menggunakannya wp_enqueue_scriptuntuk memuatnya.
phatskat

Jawaban:

18

Berikut adalah cara untuk menguji patch inti # 33300.6 oleh Andew Ozz , melalui plugin uji di WP 4.5.2, untuk mencoba filter pola teks.

Demo

Berikut ini adalah contoh dicoret menggunakan~

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

di plugin tes. Ini berfungsi seperti ini:

dicoret

Plugin uji

Struktur plugin tes adalah:

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

di mana file-file itu:

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: Digabung dengan patch # 33300.6 , menggantikan wptextpattern dengan 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 );
birgire
sumber
4
i.imgur.com/JSBTl.gif
TheDeadMedic
3
Saya memuji karya hebat oleh Andrew Ozz (azaozz) dan Ella Iseulde Van Dorpe (iseulde) , Senang sekali bisa bermain sedikit dengan filter pola teks pada versi inti yang akan datang. Terima kasih atas hasil edit @Dan.
birgire
1
Tautan ke format default sangat membantu, terima kasih @Dan - lebih banyak kemungkinan untuk bermain ;-)
birgire