Skip to content

Commit

Permalink
Merge pull request #14510 from ckeditor/ck/13866-insertParagraph-comm…
Browse files Browse the repository at this point in the history
…and-creates-additional-empty-paragraph-when-used-at-the-end-of-block-element

Fix (paragraph): The `insertParagraph` command won't insert two paragraphs when position is at the edge of the block. Closes #13866.
  • Loading branch information
Dumluregn authored Jul 10, 2023
2 parents 5c241d0 + e613d39 commit 44e8373
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 9 deletions.
40 changes: 33 additions & 7 deletions packages/ckeditor5-paragraph/src/insertparagraphcommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,46 @@ export default class InsertParagraphCommand extends Command {

model.change( writer => {
const paragraph = writer.createElement( 'paragraph' );
const allowedParent = model.schema.findAllowedParent( position, paragraph );

// It could be there's no ancestor limit that would allow paragraph.
// In theory, "paragraph" could be disallowed even in the "$root".
if ( !allowedParent ) {
return;
}

if ( attributes ) {
model.schema.setAllowedAttributes( paragraph, attributes, writer );
}

if ( !model.schema.checkChild( position.parent as Element, paragraph ) ) {
const allowedParent = model.schema.findAllowedParent( position, paragraph );
if ( position.path.length < 2 ) {
model.insertContent( paragraph, position );
writer.setSelection( paragraph, 'in' );

return;
}

const positionParent = position.parent as Element;

// E.g.
// <paragraph>[]</paragraph> ---> <paragraph></paragraph><paragraph>[]</paragraph>
const isInEmptyBlock = positionParent.isEmpty;

// E.g.
// <paragraph>foo[]</paragraph> ---> <paragraph>foo</paragraph><paragraph>[]</paragraph>
const isAtEndOfTextBlock = position.isAtEnd && !positionParent.isEmpty;

// E.g.
// <paragraph>[]foo</paragraph> ---> <paragraph>[]</paragraph><paragraph>foo</paragraph>
const isAtStartOfTextBlock = position.isAtStart && !positionParent.isEmpty;

// It could be there's no ancestor limit that would allow paragraph.
// In theory, "paragraph" could be disallowed even in the "$root".
if ( !allowedParent ) {
return;
}
const canBeChild = model.schema.checkChild( positionParent, paragraph );

if ( isInEmptyBlock || isAtEndOfTextBlock ) {
position = writer.createPositionAfter( positionParent );
} else if ( isAtStartOfTextBlock ) {
position = writer.createPositionBefore( positionParent );
} else if ( !canBeChild ) {
position = writer.split( position, allowedParent ).position;
}

Expand Down
67 changes: 67 additions & 0 deletions packages/ckeditor5-paragraph/tests/insertparagraphcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,73 @@ describe( 'InsertParagraphCommand', () => {
);
} );

it( 'should insert paragraph when position is at the end of line', () => {
setData( model, '<paragraph>foo[]</paragraph>' );

command.execute( {
position: model.document.selection.getFirstPosition()
} );

expect( getData( model ) ).to.equal(
'<paragraph>foo</paragraph>' +
'<paragraph>[]</paragraph>'
);
} );

it( 'should insert paragraph when position is at the end of line with an inline widget', () => {
schema.register( 'inlineWidget', { inheritAllFrom: '$inlineObject' } );
setData( model, '<paragraph><inlineWidget></inlineWidget>[]</paragraph>' );

command.execute( {
position: model.document.selection.getFirstPosition()
} );

expect( getData( model ) ).to.equal(
'<paragraph><inlineWidget></inlineWidget></paragraph>' +
'<paragraph>[]</paragraph>'
);
} );

it( 'should insert paragraph when position is at the start of line', () => {
setData( model, '<paragraph>[]foo</paragraph>' );

command.execute( {
position: model.document.selection.getLastPosition()
} );

expect( getData( model ) ).to.equal(
'<paragraph>[]</paragraph>' +
'<paragraph>foo</paragraph>'
);
} );

it( 'should insert paragraph when position is at the start of line with an inline widget', () => {
schema.register( 'inlineWidget', { inheritAllFrom: '$inlineObject' } );
setData( model, '<paragraph>[]<inlineWidget></inlineWidget></paragraph>' );

command.execute( {
position: model.document.selection.getLastPosition()
} );

expect( getData( model ) ).to.equal(
'<paragraph>[]</paragraph>' +
'<paragraph><inlineWidget></inlineWidget></paragraph>'
);
} );

it( 'should insert paragraph bellow when paragraph is empty', () => {
setData( model, '<paragraph>[]</paragraph>' );

command.execute( {
position: model.document.selection.getLastPosition()
} );

expect( getData( model ) ).to.equal(
'<paragraph></paragraph>' +
'<paragraph>[]</paragraph>'
);
} );

it( 'should do nothing if the paragraph is not allowed at the provided position', () => {
// Create a situation where "paragraph" is disallowed even in the "root".
schema.addChildCheck( ( context, childDefinition ) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ describe( 'WidgetTypeAround', () => {
expect( modelSelection.getAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE ) ).to.be.undefined;
} );

it( 'should split ancestors to find a place that allows a widget', () => {
it( 'should split ancestors to find a place that allows a widget (no content after widget)', () => {
model.schema.register( 'allowP', {
inheritAllFrom: '$block'
} );
Expand Down Expand Up @@ -1083,7 +1083,41 @@ describe( 'WidgetTypeAround', () => {
'<allowP>' +
'<disallowP><blockWidget></blockWidget></disallowP>' +
'<paragraph>[]</paragraph>' +
'<disallowP></disallowP>' +
'</allowP>'
);
} );

it( 'should split ancestors to find a place that allows a widget (with content after widget)', () => {
model.schema.register( 'allowP', {
inheritAllFrom: '$block'
} );
model.schema.register( 'disallowP', {
inheritAllFrom: '$block',
allowIn: [ 'allowP' ]
} );
model.schema.extend( 'blockWidget', {
allowIn: [ 'allowP', 'disallowP' ]
} );
model.schema.extend( 'paragraph', {
allowIn: [ 'allowP' ]
} );

editor.conversion.for( 'downcast' ).elementToElement( { model: 'allowP', view: 'allowP' } );
editor.conversion.for( 'downcast' ).elementToElement( { model: 'disallowP', view: 'disallowP' } );

setModelData( model,
'<allowP>' +
'<disallowP>[<blockWidget></blockWidget>]<blockWidget></blockWidget></disallowP>' +
'</allowP>'
);

fireEnter();

expect( getModelData( model ) ).to.equal(
'<allowP>' +
'<disallowP><blockWidget></blockWidget></disallowP>' +
'<paragraph>[]</paragraph>' +
'<disallowP><blockWidget></blockWidget></disallowP>' +
'</allowP>'
);
} );
Expand Down

0 comments on commit 44e8373

Please sign in to comment.