Index: src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js =================================================================== --- src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js (revision 39127) +++ src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js (working copy) @@ -46,18 +46,18 @@ ]; var inlinePatterns = settings.inline || [ - { start: '`', end: '`', format: 'code' } + { delimiter: '`', format: 'code' } ]; var canUndo; var chars = []; tinymce.each( inlinePatterns, function( pattern ) { - tinymce.each( ( pattern.start + pattern.end ).split( '' ), function( c ) { - if ( tinymce.inArray( chars, c ) === -1 ) { - chars.push( c ); - } - } ); + var c = pattern.delimiter.slice( -1 ); + + if ( tinymce.inArray( chars, c ) === -1 ) { + chars.push( c ); + } } ); editor.on( 'selectionchange', function() { @@ -108,20 +108,36 @@ var string = node.data.slice( 0, offset ); tinymce.each( inlinePatterns, function( p ) { - var regExp = new RegExp( escapeRegExp( p.start ) + '\\S+' + escapeRegExp( p.end ) + '$' ); + var regExp = new RegExp( + // Optional and greedy to push match back to end + '(.*)' + + // Start delimiter + escapeRegExp( p.delimiter ) + + // Non whitespace, non delimiter character + '[^\\s' + escapeRegExp( p.delimiter.slice( -1 ) ) + ']' + + // Optional characters + '.*' + + // Optional non whitespace, non delimiter character + '[^\\s' + escapeRegExp( p.delimiter.slice( 0, 1 ) ) + ']' + + // End delimiter + escapeRegExp( p.delimiter ) + + // End of string + '$' + ); + var match = string.match( regExp ); if ( ! match ) { return; } - // Don't allow pattern characters in the text. - if ( node.data.slice( match.index + p.start.length, offset - p.end.length ).indexOf( p.start.slice( 0, 1 ) ) !== -1 ) { + startOffset = match.index + match[1].length; + endOffset = offset - p.delimiter.length; + + if ( startOffset && ( new RegExp( escapeRegExp( p.delimiter.slice( 0, 1 ) ) ) ).test( node.data.charAt( startOffset - 1 ) ) ) { return; } - startOffset = match.index; - endOffset = offset - p.end.length; pattern = p; return false; @@ -142,8 +158,8 @@ 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 ); + node.deleteData( 0, pattern.delimiter.length ); + node.deleteData( node.data.length - pattern.delimiter.length, pattern.delimiter.length ); editor.formatter.apply( pattern.format, {}, node ); Index: tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js =================================================================== --- tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js (revision 39127) +++ tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js (working copy) @@ -157,8 +157,8 @@ plugins: 'wptextpattern', wptextpattern: { inline: [ - { start: '`', end: '`', format: 'code' }, - { start: '``', end: '``', format: 'bold' } + { delimiter: '`', format: 'code' }, + { delimiter: '``', format: 'bold' } ] }, init_instance_callback: function() { @@ -319,6 +319,27 @@ }, assert.async() ); } ); + QUnit.test( 'Inline: allow spaces', function( assert ) { + type( '`a a`', function() { + assert.equal( editor.getContent(), '
a a
a`a
' ); + assert.equal( editor.selection.getRng().startOffset, 1 ); + }, assert.async() ); + } ); + + QUnit.test( 'Inline: previous character should not be non space', function( assert ) { + type( 'a`a`', function() { + assert.equal( editor.getContent(), 'a`a`
' ); + assert.equal( editor.selection.getRng().startOffset, 4 ); + }, assert.async() ); + } ); + QUnit.test( 'Inline: after typing.', function( assert ) { editor.setContent( 'test test test
' ); editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 5 );