diff --git a/src/deletecommand.js b/src/deletecommand.js index 805d026..d5349a8 100644 --- a/src/deletecommand.js +++ b/src/deletecommand.js @@ -10,6 +10,9 @@ import Command from '@ckeditor/ckeditor5-core/src/command'; import Selection from '@ckeditor/ckeditor5-engine/src/model/selection'; import ChangeBuffer from './changebuffer'; +import Position from '@ckeditor/ckeditor5-engine/src/model/position'; +import Element from '@ckeditor/ckeditor5-engine/src/model/element'; +import Range from '@ckeditor/ckeditor5-engine/src/model/range'; import count from '@ckeditor/ckeditor5-utils/src/count'; /** @@ -60,6 +63,8 @@ export default class DeleteCommand extends Command { execute( options = {} ) { const doc = this.editor.document; const dataController = this.editor.data; + const root = doc.getRoot(); + const schema = doc.schema; doc.enqueueChanges( () => { this._buffer.lock(); @@ -90,6 +95,25 @@ export default class DeleteCommand extends Command { doc.selection.setRanges( selection.getRanges(), selection.isBackward ); this._buffer.unlock(); + + // Check whether the whole content has been removed and whether schema allows inserting a paragraph. + // If the user will typing after removing the whole content, the user's input should be wrapped in the paragraph + // instead of any other element. See https://github.com/ckeditor/ckeditor5-typing/issues/61. + if ( + Position.createAt( root ).isTouching( selection.getFirstPosition() ) && + Position.createAt( root, 'end' ).isTouching( selection.getLastPosition() ) && + schema.check( { name: 'paragraph', inside: root.name } ) + ) { + this._buffer.batch.remove( + new Range( new Position( root, [ 0 ] ), new Position( root, [ 1 ] ) ) + ); + + this._buffer.batch.insert( + new Position( root, [ 0 ] ), new Element( 'paragraph' ) + ); + + doc.selection.setRanges( new Range( new Position( root, [ 0 ] ) ) ); + } } ); } } diff --git a/tests/inputcommand-integration.js b/tests/inputcommand-integration.js index bdce04e..3419832 100644 --- a/tests/inputcommand-integration.js +++ b/tests/inputcommand-integration.js @@ -13,6 +13,7 @@ import Undo from '@ckeditor/ckeditor5-undo/src/undo'; import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold'; import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic'; import Enter from '@ckeditor/ckeditor5-enter/src/enter'; +import Heading from '@ckeditor/ckeditor5-heading/src/heading'; import Range from '@ckeditor/ckeditor5-engine/src/model/range'; import Position from '@ckeditor/ckeditor5-engine/src/model/position'; @@ -28,7 +29,7 @@ describe( 'InputCommand integration', () => { document.body.appendChild( editorElement ); return ClassicTestEditor.create( editorElement, { - plugins: [ Typing, Paragraph, Undo, Bold, Italic, Enter ], + plugins: [ Typing, Paragraph, Undo, Bold, Italic, Enter, Heading ], typing: { undoStep: 3 } } ) .then( newEditor => { @@ -210,5 +211,45 @@ describe( 'InputCommand integration', () => { expectOutput( 'Foo <$text bold="true">B[] Bar', '

Foo B{} Bar

' ); } ); + + // See https://github.com/ckeditor/ckeditor5-typing/issues/61. + it( 'leaves an empty paragraph after removing the whole content from editor #1', () => { + setModelData( doc, '[Header 1Some text.]' ); + + editor.execute( 'delete' ); + + expectOutput( '[]', '

[]

' ); + } ); + + // See https://github.com/ckeditor/ckeditor5-typing/issues/61. + it( 'leaves an empty paragraph after removing the whole content from editor #2', () => { + setModelData( doc, '[Header 1Some text.]' ); + + editor.execute( 'delete' ); + + expectOutput( '[]', '

[]

' ); + } ); + + // See https://github.com/ckeditor/ckeditor5-typing/issues/61. + it( 'wraps inserted text in a paragraph after typing in editor with selected the whole content #1', () => { + setModelData( doc, '[Header 1Some text.]' ); + + editor.execute( 'delete' ); + + simulateTyping( '123' ); + + expectOutput( '123[]', '

123{}

' ); + } ); + + // See https://github.com/ckeditor/ckeditor5-typing/issues/61. + it( 'wraps inserted text in a paragraph after typing in editor with selected the whole content #2', () => { + setModelData( doc, '[Header 1Some text.]' ); + + editor.execute( 'delete' ); + + simulateTyping( '123' ); + + expectOutput( '123[]', '

123{}

' ); + } ); } ); } );