diff --git a/src/blockautoformatediting.js b/src/blockautoformatediting.js index 92e5f7f..09593fb 100644 --- a/src/blockautoformatediting.js +++ b/src/blockautoformatediting.js @@ -88,14 +88,16 @@ export default class BlockAutoformatEditing { return; } - const item = entry.position.textNode || entry.position.nodeAfter; + const blockToFormat = entry.position.parent; - if ( !item.parent.is( 'paragraph' ) ) { + // Block formatting should trigger only if the entire content of a paragraph is a single text node... (see ckeditor5#5671). + if ( !blockToFormat.is( 'paragraph' ) || blockToFormat.childCount !== 1 ) { return; } - const match = pattern.exec( item.data ); + const match = pattern.exec( blockToFormat.getChild( 0 ).data ); + // ...and this text node's data match the pattern. if ( !match ) { return; } @@ -103,8 +105,8 @@ export default class BlockAutoformatEditing { // Use enqueueChange to create new batch to separate typing batch from the auto-format changes. editor.model.enqueueChange( writer => { // Matched range. - const start = writer.createPositionAt( item.parent, 0 ); - const end = writer.createPositionAt( item.parent, match[ 0 ].length ); + const start = writer.createPositionAt( blockToFormat, 0 ); + const end = writer.createPositionAt( blockToFormat, match[ 0 ].length ); const range = new LiveRange( start, end ); const wasChanged = callback( { match } ); diff --git a/tests/autoformat.js b/tests/autoformat.js index 22a4543..bca08db 100644 --- a/tests/autoformat.js +++ b/tests/autoformat.js @@ -81,6 +81,15 @@ describe( 'Autoformat', () => { expect( getData( model ) ).to.equal( '- []' ); } ); + + it( 'should not replace asterisk character after ', () => { + setData( model, 'Foo*[]' ); + model.change( writer => { + writer.insertText( ' ', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to.equal( 'Foo* []' ); + } ); } ); describe( 'Numbered list', () => { @@ -128,6 +137,15 @@ describe( 'Autoformat', () => { expect( getData( model ) ).to.equal( '3. []' ); } ); + + it( 'should not replace digit character after ', () => { + setData( model, 'Foo1.[]' ); + model.change( writer => { + writer.insertText( ' ', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to.equal( 'Foo1. []' ); + } ); } ); describe( 'Heading', () => { @@ -212,6 +230,15 @@ describe( 'Autoformat', () => { expect( getData( model ) ).to.equal( '# []' ); } ); + + it( 'should not replace hash character after ', () => { + setData( model, 'Foo#[]' ); + model.change( writer => { + writer.insertText( ' ', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to.equal( 'Foo# []' ); + } ); } ); describe( 'Block quote', () => { @@ -250,6 +277,15 @@ describe( 'Autoformat', () => { expect( getData( model ) ).to.equal( '1. > []' ); } ); + + it( 'should not replace greater-than character after ', () => { + setData( model, 'Foo>[]' ); + model.change( writer => { + writer.insertText( ' ', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to.equal( 'Foo> []' ); + } ); } ); describe( 'Inline autoformat', () => { diff --git a/tests/blockautoformatediting.js b/tests/blockautoformatediting.js index 2a62c58..27b5c6c 100644 --- a/tests/blockautoformatediting.js +++ b/tests/blockautoformatediting.js @@ -128,6 +128,63 @@ describe( 'BlockAutoformatEditing', () => { sinon.assert.notCalled( spy ); } ); + it( 'should not call callback when after inline element', () => { + // Configure the schema. + model.schema.register( 'softBreak', { + allowWhere: '$text', + isInline: true + } ); + editor.conversion.for( 'upcast' ) + .elementToElement( { + model: 'softBreak', + view: 'br' + } ); + editor.conversion.for( 'downcast' ) + .elementToElement( { + model: 'softBreak', + view: ( modelElement, viewWriter ) => viewWriter.createEmptyElement( 'br' ) + } ); + + const spy = testUtils.sinon.spy(); + new BlockAutoformatEditing( editor, /^[*]\s/, spy ); // eslint-disable-line no-new + + setData( model, '*[]' ); + model.change( writer => { + writer.insertText( ' ', doc.selection.getFirstPosition() ); + } ); + + sinon.assert.notCalled( spy ); + } ); + + it( 'should not call callback when after inline element (typing after softBreak in a "matching" paragraph)', () => { + // Configure the schema. + model.schema.register( 'softBreak', { + allowWhere: '$text', + isInline: true + } ); + editor.conversion.for( 'upcast' ) + .elementToElement( { + model: 'softBreak', + view: 'br' + } ); + editor.conversion.for( 'downcast' ) + .elementToElement( { + model: 'softBreak', + view: ( modelElement, viewWriter ) => viewWriter.createEmptyElement( 'br' ) + } ); + + const spy = testUtils.sinon.spy(); + new BlockAutoformatEditing( editor, /^[*]\s/, spy ); // eslint-disable-line no-new + + setData( model, '* []' ); + + model.change( writer => { + writer.insertText( ' ', doc.selection.getFirstPosition() ); + } ); + + sinon.assert.notCalled( spy ); + } ); + it( 'should stop if callback returned false', () => { new BlockAutoformatEditing( editor, /^[*]\s$/, () => false ); // eslint-disable-line no-new