diff --git a/src/controller/insertcontent.js b/src/controller/insertcontent.js
index 52a2e9902..c5ba075aa 100644
--- a/src/controller/insertcontent.js
+++ b/src/controller/insertcontent.js
@@ -354,6 +354,11 @@ class Insertion {
}
if ( this._checkIsAllowed( node, [ paragraph ] ) ) {
+ // Prevent having same node in two parents.
+ if ( node.parent ) {
+ node.remove();
+ }
+
paragraph.appendChildren( node );
this._handleNode( paragraph, context );
}
diff --git a/src/view/writer.js b/src/view/writer.js
index ec16ee8b0..b350f5cf1 100644
--- a/src/view/writer.js
+++ b/src/view/writer.js
@@ -212,7 +212,7 @@ export function mergeAttributes( position ) {
else if ( nodeBefore.is( 'attributeElement' ) && nodeAfter.is( 'attributeElement' ) && nodeBefore.isSimilar( nodeAfter ) ) {
// Move all children nodes from node placed after selection and remove that node.
const count = nodeBefore.childCount;
- nodeBefore.appendChildren( nodeAfter.getChildren() );
+ nodeBefore.appendChildren( nodeAfter.removeChildren( 0, nodeAfter.childCount ) );
nodeAfter.remove();
// New position is located inside the first node, before new nodes.
@@ -831,8 +831,8 @@ function unwrapChildren( parent, startOffset, endOffset, attribute ) {
// If attributes are the similar, then unwrap.
if ( child.isSimilar( attribute ) ) {
- const unwrapped = child.getChildren();
const count = child.childCount;
+ const unwrapped = child.removeChildren( 0, count );
// Replace wrapper element with its children
child.remove();
@@ -904,7 +904,7 @@ function wrapChildren( parent, startOffset, endOffset, attribute ) {
// Clone attribute.
const newAttribute = attribute.clone();
- // Wrap current node with new attribute;
+ // Wrap current node with new attribute.
child.remove();
newAttribute.appendChildren( child );
parent.insertChildren( i, newAttribute );
diff --git a/tests/controller/insertcontent.js b/tests/controller/insertcontent.js
index 64d0373af..476a31135 100644
--- a/tests/controller/insertcontent.js
+++ b/tests/controller/insertcontent.js
@@ -294,6 +294,16 @@ describe( 'DataController', () => {
expect( getData( doc ) ).to.equal( 'bar[]' );
} );
+ it( 'autoparagraphs when just text is inserted', () => {
+ doc.schema.disallow( { name: '$text', inside: 'blockWidget' } );
+ doc.schema.allow( { name: 'paragraph', inside: 'blockWidget' } );
+
+ setData( doc, '[]' );
+ insertContent( dataController, new Text( 'foo' ), doc.selection );
+
+ expect( getData( doc ) ).to.equal( 'foo[]' );
+ } );
+
describe( 'block to block handling', () => {
it( 'inserts one paragraph', () => {
setData( doc, 'f[]oo' );
diff --git a/tests/view/writer/mergeattributes.js b/tests/view/writer/mergeattributes.js
index caa908fe5..d71d36a3b 100644
--- a/tests/view/writer/mergeattributes.js
+++ b/tests/view/writer/mergeattributes.js
@@ -143,5 +143,18 @@ describe( 'writer', () => {
'[]'
);
} );
+
+ it( 'should correctly move nodes when merging', () => {
+ // Check if nodes has been removed from old parent before adding to new parent.
+ const { view, selection } = parse(
+ 'foo[]bar'
+ );
+
+ const b = view.getChild( 1 );
+
+ mergeAttributes( selection.getFirstPosition() );
+
+ expect( b.childCount ).to.equal( 0 );
+ } );
} );
} );
diff --git a/tests/view/writer/unwrap.js b/tests/view/writer/unwrap.js
index 217c526a5..aab15373f 100644
--- a/tests/view/writer/unwrap.js
+++ b/tests/view/writer/unwrap.js
@@ -83,6 +83,16 @@ describe( 'writer', () => {
} ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
} );
+ it( 'should correctly move unwrapped nodes', () => {
+ // Check if nodes has been removed from old parent before adding to new parent.
+ const { view, selection } = parse( '[x]' );
+ const b = view.getChild( 0 );
+
+ unwrap( selection.getFirstRange(), parse( '' ) );
+
+ expect( b.childCount ).to.equal( 0 );
+ } );
+
it( 'should unwrap single node', () => {
test(
'[foobar]',