WordPress.org

Make WordPress Core

Ticket #37693: 37693.12.patch

File 37693.12.patch, 7.7 KB (added by azaozz, 4 years ago)
  • src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js

     
    33 *
    44 * @since 4.3.0
    55 *
    6  * This plugin can automatically format text patterns as you type. It includes two patterns:
     6 * This plugin can automatically format text patterns as you type. It includes several groups of patterns.
     7 * Start of line patterns:
     8 *  As-you-type:
    79 *  - Unordered list (`* ` and `- `).
    810 *  - Ordered list (`1. ` and `1) `).
    911 *
     12 *  On enter:
     13 *  - h2 (## ).
     14 *  - h3 (### ).
     15 *  - h4 (#### ).
     16 *  - h5 (##### ).
     17 *  - h6 (###### ).
     18 *  - blockquote (> ).
     19 *  - hr (---).
     20 *
     21 * Inline patterns:
     22 *  - <code> (`) (backtick).
     23 *
    1024 * If the transformation in unwanted, the user can undo the change by pressing backspace,
    1125 * using the undo shortcut, or the undo button in the toolbar.
     26 *
     27 * Setting for the patterns can be overridden by plugins by using the `tiny_mce_before_init` PHP filter.
     28 * The setting name is `wptextpattern` and the value is an object containing override arrays for each
     29 * patterns group. There are three groups: "space", "enter", and "inline". Example (PHP):
     30 *
     31 * add_filter( 'tiny_mce_before_init', 'my_mce_init_wptextpattern' );
     32 * function my_mce_init_wptextpattern( $init ) {
     33 *   $init['wptextpattern'] = wp_json_encode( array(
     34 *      'inline' => array(
     35 *        array( 'delimiter' => '**', 'format' => 'bold' ),
     36 *        array( 'delimiter' => '__', 'format' => 'italic' ),
     37 *      ),
     38 *   ) );
     39 *
     40 *   return $init;
     41 * }
     42 *
     43 * Note that setting this will override the default text patterns. You will need to include them
     44 * in your settings array if you want to keep them working.
    1245 */
    1346( function( tinymce, setTimeout ) {
    1447        if ( tinymce.Env.ie && tinymce.Env.ie < 9 ) {
     
    4679                ];
    4780
    4881                var inlinePatterns = settings.inline || [
    49                         { start: '`', end: '`', format: 'code' }
     82                        { delimiter: '`', format: 'code' }
    5083                ];
    5184
    5285                var canUndo;
     
    5386                var chars = [];
    5487
    5588                tinymce.each( inlinePatterns, function( pattern ) {
    56                         tinymce.each( ( pattern.start + pattern.end ).split( '' ), function( c ) {
    57                                 if ( tinymce.inArray( chars, c ) === -1 ) {
    58                                         chars.push( c );
    59                                 }
    60                         } );
     89                        var c = pattern.delimiter.slice( -1 );
     90
     91                        if ( tinymce.inArray( chars, c ) === -1 ) {
     92                                chars.push( c );
     93                        }
    6194                } );
    6295
    6396                editor.on( 'selectionchange', function() {
     
    108141                        var string = node.data.slice( 0, offset );
    109142
    110143                        tinymce.each( inlinePatterns, function( p ) {
    111                                 var regExp = new RegExp( escapeRegExp( p.start ) + '\\S+' + escapeRegExp( p.end ) + '$' );
     144                                var escDelimiter = escapeRegExp( p.delimiter );
     145                                var delimiterFirstChar = p.delimiter.charAt( 0 );
     146                                var regExp = new RegExp( '(.*)' + escDelimiter + '.+' + escDelimiter + '$' );
    112147                                var match = string.match( regExp );
    113148
    114149                                if ( ! match ) {
     
    115150                                        return;
    116151                                }
    117152
    118                                 // Don't allow pattern characters in the text.
    119                                 if ( node.data.slice( match.index + p.start.length, offset - p.end.length ).indexOf( p.start.slice( 0, 1 ) ) !== -1 ) {
     153                                startOffset = match[1].length;
     154                                endOffset = offset - p.delimiter.length;
     155
     156                                var before = string.charAt( startOffset - 1 );
     157                                var after = string.charAt( startOffset + p.delimiter.length );
     158
     159                                // test*test* => format applied
     160                                // test *test* => applied
     161                                // test* test* => not applied
     162                                if ( startOffset && /\S/.test( before ) ) {
     163                                        if ( /\s/.test( after ) || before === delimiterFirstChar ) {
     164                                                return;
     165                                        }
     166                                }
     167
     168                                // Do not replace when only whitespace and delimiter characters.
     169                                if ( ( new RegExp( '^[\\s' + escapeRegExp( delimiterFirstChar ) + ']+$' ) ).test( string.slice( startOffset, endOffset ) ) ) {
    120170                                        return;
    121171                                }
    122172
    123                                 startOffset = match.index;
    124                                 endOffset = offset - p.end.length;
    125173                                pattern = p;
    126174
    127175                                return false;
     
    142190                                        node = node.splitText( startOffset );
    143191                                        zero = node.splitText( offset - startOffset );
    144192
    145                                         node.deleteData( 0, pattern.start.length );
    146                                         node.deleteData( node.data.length - pattern.end.length, pattern.end.length );
     193                                        node.deleteData( 0, pattern.delimiter.length );
     194                                        node.deleteData( node.data.length - pattern.delimiter.length, pattern.delimiter.length );
    147195
    148196                                        editor.formatter.apply( pattern.format, {}, node );
    149197
  • tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js

     
    157157                                        plugins: 'wptextpattern',
    158158                                        wptextpattern: {
    159159                                                inline: [
    160                                                         { start: '`', end: '`', format: 'code' },
    161                                                         { start: '``', end: '``', format: 'bold' }
     160                                                        { delimiter: '`', format: 'code' },
     161                                                        { delimiter: '``', format: 'bold' },
     162                                                        { delimiter: '```', format: 'italic' }
    162163                                                ]
    163164                                        },
    164165                                        init_instance_callback: function() {
     
    319320                }, assert.async() );
    320321        } );
    321322
     323        QUnit.test( 'Inline: allow spaces within text.', function( assert ) {
     324                type( '`a a`', function() {
     325                        assert.equal( editor.getContent(), '<p><code>a a</code></p>' );
     326                        assert.equal( editor.selection.getRng().startOffset, 1 );
     327                }, assert.async() );
     328        } );
     329
     330        QUnit.test( 'Inline: disallow \\S-delimiter-\\s.', function( assert ) {
     331                type( 'a` a`', function() {
     332                        assert.equal( editor.getContent(), '<p>a` a`</p>' );
     333                        assert.equal( editor.selection.getRng().startOffset, 5 );
     334                }, assert.async() );
     335        } );
     336
     337        QUnit.test( 'Inline: allow \\s-delimiter-\\s.', function( assert ) {
     338                type( 'a ` a`', function() {
     339                        assert.equal( editor.getContent(), '<p>a <code> a</code></p>' );
     340                        assert.equal( editor.selection.getRng().startOffset, 1 );
     341                }, assert.async() );
     342        } );
     343
     344        QUnit.test( 'Inline: allow \\S-delimiter-\\S.', function( assert ) {
     345                type( 'a`a`', function() {
     346                        assert.equal( editor.getContent(), '<p>a<code>a</code></p>' );
     347                        assert.equal( editor.selection.getRng().startOffset, 1 );
     348                }, assert.async() );
     349        } );
     350
    322351        QUnit.test( 'Inline: after typing.', function( assert ) {
    323352                editor.setContent( '<p>test test test</p>' );
    324353                editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 5 );
     
    337366                }, assert.async() );
    338367        } );
    339368
    340         QUnit.test( 'Convert with previously unconverted pattern', function( assert ) {
     369        QUnit.test( 'Convert with previously unconverted pattern.', function( assert ) {
    341370                editor.setContent( '<p>`test` test&nbsp;</p>' );
    342371                editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 12 );
    343372
     
    345374                        assert.equal( editor.getContent(), '<p>`test` test&nbsp;<code>test</code></p>' );
    346375                }, assert.async() );
    347376        } );
     377
     378        QUnit.test( 'Convert with long pattern after previous pattern characters.', function( assert ) {
     379                editor.setContent( '<p>test``` 123</p>' );
     380                editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 11 );
     381
     382                type( '``456``', function() {
     383                        assert.equal( editor.getContent(), '<p>test``` 123<strong>456</strong></p>' );
     384                }, assert.async() );
     385        } );
     386
     387        QUnit.test( 'Inline: no change with long pattern after previous pattern characters and leading space.', function( assert ) {
     388                editor.setContent( '<p>test``` 123</p>' );
     389                editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 11 );
     390
     391                type( '``` 456```', function() {
     392                        assert.equal( editor.getContent(), '<p>test``` 123``` 456```</p>' );
     393                }, assert.async() );
     394        } );
    348395} )( window.jQuery, window.QUnit, window.tinymce, window.setTimeout );