diff --git a/packages/ckeditor5-autoformat/src/inlineautoformatediting.js b/packages/ckeditor5-autoformat/src/inlineautoformatediting.js index 0538ccf43d2..5e230376a41 100644 --- a/packages/ckeditor5-autoformat/src/inlineautoformatediting.js +++ b/packages/ckeditor5-autoformat/src/inlineautoformatediting.js @@ -7,8 +7,6 @@ * @module autoformat/inlineautoformatediting */ -import getLastTextLine from '@ckeditor/ckeditor5-typing/src/utils/getlasttextline'; - /** * The inline autoformatting engine. It allows to format various inline patterns. For example, * it can be configured to make "foo" bold when typed `**foo**` (the `**` markers will be removed). @@ -174,7 +172,7 @@ export default class InlineAutoformatEditing { const focus = selection.focus; const block = focus.parent; - const { text, range } = getLastTextLine( model.createRange( model.createPositionAt( block, 0 ), focus ), model ); + const { text, range } = getTextAfterCode( model.createRange( model.createPositionAt( block, 0 ), focus ), model ); const testOutput = testCallback( text ); const rangesToFormat = testOutputToRanges( range.start, testOutput.format, model ); const rangesToRemove = testOutputToRanges( range.start, testOutput.remove, model ); @@ -216,3 +214,27 @@ function testOutputToRanges( start, arrays, model ) { return model.createRange( start.getShiftedBy( array[ 0 ] ), start.getShiftedBy( array[ 1 ] ) ); } ); } + +// Returns the last text line after the last code element from the given range. +// It is similar to {@link module:typing/utils/getlasttextline.getLastTextLine `getLastTextLine()`}, +// but it ignores any text before the last `code`. +// +// @param {module:engine/model/range~Range} range +// @param {module:engine/model/model~Model} model +// @returns {module:typing/utils/getlasttextline~LastTextLineData} +function getTextAfterCode( range, model ) { + let start = range.start; + + const text = Array.from( range.getItems() ).reduce( ( rangeText, node ) => { + // Trim text to a last occurrence of an inline element and update range start. + if ( !( node.is( 'text' ) || node.is( 'textProxy' ) ) || node.getAttribute( 'code' ) ) { + start = model.createPositionAfter( node ); + + return ''; + } + + return rangeText + node.data; + }, '' ); + + return { text, range: model.createRange( start, range.end ) }; +} diff --git a/packages/ckeditor5-autoformat/tests/autoformat.js b/packages/ckeditor5-autoformat/tests/autoformat.js index bc4d309d275..777a4fbb46d 100644 --- a/packages/ckeditor5-autoformat/tests/autoformat.js +++ b/packages/ckeditor5-autoformat/tests/autoformat.js @@ -422,6 +422,134 @@ describe( 'Autoformat', () => { expect( getData( model ) ).to.equal( '**foobar**[]' ); } ); + describe( 'with code element', () => { + it( 'should not format inside', () => { + // Test *. + setData( model, '<$text code="true">fo*obar[]$text>' ); + + model.change( writer => { + writer.insertText( '*', { code: true }, doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo*obar*[]$text>' ); + + // Test __. + setData( model, '<$text code="true">fo__obar_[]$text>' ); + + model.change( writer => { + writer.insertText( '_', { code: true }, doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo__obar__[]$text>' ); + + // Test ~~. + setData( model, '<$text code="true">fo~~obar~[]$text>' ); + + model.change( writer => { + writer.insertText( '~', { code: true }, doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo~~obar~~[]$text>' ); + + // Test `. + setData( model, '<$text code="true">fo`obar[]$text>' ); + + model.change( writer => { + writer.insertText( '`', { code: true }, doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo`obar`[]$text>' ); + } ); + + it( 'should not format across', () => { + // Test *. + setData( model, '<$text code="true">fo*o$text>bar[]' ); + + model.change( writer => { + writer.insertText( '*', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo*o$text>bar*[]' ); + + // Test __. + setData( model, '<$text code="true">fo__o$text>bar_[]' ); + + model.change( writer => { + writer.insertText( '_', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo__o$text>bar__[]' ); + + // Test ~~. + setData( model, '<$text code="true">fo~~o$text>bar~[]' ); + + model.change( writer => { + writer.insertText( '~', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo~~o$text>bar~~[]' ); + + // Test `. + setData( model, '<$text code="true">fo`o$text>bar[]' ); + + model.change( writer => { + writer.insertText( '`', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo`o$text>bar`[]' ); + } ); + + it( 'should format after', () => { + // Test *. + setData( model, '<$text code="true">fo*o$text>b*ar[]' ); + + model.change( writer => { + writer.insertText( '*', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo*o$text>b<$text italic="true">ar$text>[]' ); + + // Test __. + setData( model, '<$text code="true">fo__o$text>b__ar_[]' ); + + model.change( writer => { + writer.insertText( '_', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo__o$text>b<$text bold="true">ar$text>[]' ); + + // Test ~~. + setData( model, '<$text code="true">fo~~o$text>b~~ar~[]' ); + + model.change( writer => { + writer.insertText( '~', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo~~o$text>b<$text strikethrough="true">ar$text>[]' ); + + // Test `. + setData( model, '<$text code="true">fo`o$text>b`ar[]' ); + + model.change( writer => { + writer.insertText( '`', doc.selection.getFirstPosition() ); + } ); + + expect( getData( model ) ).to + .equal( '<$text code="true">fo`o$text>b<$text code="true">ar$text>[]' ); + } ); + } ); + it( 'should work with s in paragraph', () => { setData( model, 'foo**barbaz*[]' ); model.change( writer => { diff --git a/packages/ckeditor5-autoformat/tests/manual/autoformat.html b/packages/ckeditor5-autoformat/tests/manual/autoformat.html index 01a316e470f..c0b3eb937ed 100644 --- a/packages/ckeditor5-autoformat/tests/manual/autoformat.html +++ b/packages/ckeditor5-autoformat/tests/manual/autoformat.html @@ -1,3 +1,3 @@ - This is the editor instance. + This is the editor instance, with a code_element*2; inside.
This is the editor instance.
This is the editor instance, with a code_element*2; inside.
code_element*2;