From 34354fc3c0262743aa17cae186b5fe1c2b6f5c96 Mon Sep 17 00:00:00 2001 From: Ella Iseulde Van Dorpe Date: Mon, 27 Jul 2015 23:15:15 +0000 Subject: [PATCH] TinyMCE: wptextpattern: headings on enter Fixes #31441. git-svn-id: https://develop.svn.wordpress.org/trunk@33452 602fd350-edb4-49c9-b593-d223f7449a82 --- .../tinymce/plugins/wptextpattern/plugin.js | 150 +++++++++++------- .../tinymce/plugins/wptextpattern/plugin.js | 27 ++++ 2 files changed, 117 insertions(+), 60 deletions(-) diff --git a/src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js b/src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js index 994ed50edb..03e2cad79c 100644 --- a/src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js +++ b/src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js @@ -14,39 +14,19 @@ tinymce.PluginManager.add( 'wptextpattern', function( editor ) { var $$ = editor.$, VK = tinymce.util.VK, - patterns = [], - canUndo = false; - - /** - * Add a pattern to format with a callback. - * - * @since 4.3.0 - * - * @param {RegExp} regExp RegEx pattern. - * @param {Function} callback Callback. - */ - function add( regExp, callback ) { - patterns.push( { - regExp: regExp, - callback: callback - } ); - } - - add( /^[*-]\s/, function() { - this.execCommand( 'InsertUnorderedList' ); - } ); - - add( /^1[.)]\s/, function() { - this.execCommand( 'InsertOrderedList' ); - } ); - - add( /^>\s/, function() { - this.formatter.toggle( 'blockquote' ); - } ); - - add( /^(#{2,6})\s/, function() { - this.formatter.toggle( 'h' + arguments[1].length ); - } ); + canUndo = false, + spacePatterns = [ + { regExp: /^[*-]\s/, cmd: 'InsertUnorderedList' }, + { regExp: /^1[.)]\s/, cmd: 'InsertOrderedList' } + ], + enterPatterns = [ + { start: '##', format: 'h2' }, + { start: '###', format: 'h3' }, + { start: '####', format: 'h4' }, + { start: '#####', format: 'h5' }, + { start: '######', format: 'h6' }, + { start: '>', format: 'blockquote' } + ]; editor.on( 'selectionchange', function() { canUndo = false; @@ -57,24 +37,21 @@ editor.undoManager.undo(); event.preventDefault(); } - } ); + + if ( event.keyCode === VK.ENTER && ! VK.modifierPressed( event ) ) { + enter(); + } + }, true ); editor.on( 'keyup', function( event ) { - var rng, node, text, parent, child; - - if ( event.keyCode !== VK.SPACEBAR ) { - return; + if ( event.keyCode === VK.SPACEBAR || ! VK.modifierPressed( event ) ) { + space(); } + } ); - rng = editor.selection.getRng(); - node = rng.startContainer; - - if ( ! node || node.nodeType !== 3 ) { - return; - } - - text = node.nodeValue; - parent = editor.dom.getParent( node, 'p' ); + function firstNode( node ) { + var parent = editor.dom.getParent( node, 'p' ), + child; if ( ! parent ) { return; @@ -92,20 +69,26 @@ return; } - if ( ! child.nodeValue ) { + if ( ! child.data ) { child = child.nextSibling; } - if ( child !== node ) { + return child; + } + + function space() { + var rng = editor.selection.getRng(), + node = rng.startContainer, + text; + + if ( firstNode( node ) !== node ) { return; } - tinymce.each( patterns, function( pattern ) { - var args, - replace = text.replace( pattern.regExp, function() { - args = arguments; - return ''; - } ); + text = node.data; + + tinymce.each( spacePatterns, function( pattern ) { + var replace = text.replace( pattern.regExp, '' ); if ( text === replace ) { return; @@ -118,12 +101,13 @@ editor.undoManager.add(); editor.undoManager.transact( function() { - var $$parent; + var parent = node.parentNode, + $$parent; if ( replace ) { $$( node ).replaceWith( document.createTextNode( replace ) ); } else { - $$parent = $$( node.parentNode ); + $$parent = $$( parent ); $$( node ).remove(); @@ -133,8 +117,7 @@ } editor.selection.setCursorLocation( parent ); - - pattern.callback.apply( editor, args ); + editor.execCommand( pattern.cmd ); } ); // We need to wait for native events to be triggered. @@ -144,6 +127,53 @@ return false; } ); - } ); + } + + function enter() { + var selection = editor.selection, + rng = selection.getRng(), + offset = rng.startOffset, + start = rng.startContainer, + node = firstNode( start ), + i = enterPatterns.length, + text, pattern; + + if ( ! node ) { + return; + } + + text = node.data; + + while ( i-- ) { + if ( text.indexOf( enterPatterns[ i ].start ) === 0 ) { + pattern = enterPatterns[ i ]; + break; + } + } + + if ( ! pattern ) { + return; + } + + if ( node === start ) { + if ( tinymce.trim( text ) === pattern.start ) { + return; + } + + offset = Math.max( 0, offset - pattern.start.length ); + } + + editor.undoManager.add(); + + editor.undoManager.transact( function() { + node.deleteData( 0, pattern.start.length ); + + editor.formatter.apply( pattern.format, {}, start ); + + rng.setStart( start, offset ); + rng.collapse( true ); + selection.setRng( rng ); + } ); + } } ); } )( window.tinymce, window.setTimeout ); diff --git a/tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js b/tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js index 0c84e7b823..2f72339b8d 100644 --- a/tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js +++ b/tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js @@ -144,4 +144,31 @@ assert.equal( editor.getContent(), '' ); }, assert.async() ); } ); + + QUnit.test( 'Heading 3', function( assert ) { + editor.setContent( '

### test

' ); + editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 8 ); + + type( '\n', function() { + assert.equal( editor.getContent(), '

test

\n

 

' ); + }, assert.async() ); + } ); + + QUnit.test( 'Heading 3 with elements.', function( assert ) { + editor.setContent( '

###test

' ); + editor.selection.setCursorLocation( editor.$( 'del' )[0].firstChild, 4 ); + + type( '\n', function() { + assert.equal( editor.getContent(), '

test

\n

 

' ); + }, assert.async() ); + } ); + + QUnit.test( 'Don\'t convert without content', function( assert ) { + editor.setContent( '

### 

' ); + editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 4 ); + + type( '\n', function() { + assert.equal( editor.getContent(), '

### 

\n

 

' ); + }, assert.async() ); + } ); } )( window.jQuery, window.QUnit, window.tinymce, window.Utils.type, window.setTimeout );