Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1260 from ckeditor/t/730
Browse files Browse the repository at this point in the history
Fix: `Model#insertContent()` will not merge nodes if the model after the merge would violate schema rules. Closes ckeditor/ckeditor5#730.
  • Loading branch information
Reinmar authored Feb 1, 2018
2 parents fb02992 + 0e2fc86 commit 2a73830
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 2 deletions.
46 changes: 44 additions & 2 deletions src/model/utils/insertcontent.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ class Insertion {
}

/**
* @private
* Handles insertion of a single node.
*
* @param {module:engine/model/node~Node} node
Expand Down Expand Up @@ -211,6 +212,7 @@ class Insertion {
}

/**
* @private
* @param {module:engine/model/element~Element} node The object element.
* @param {Object} context
*/
Expand All @@ -226,6 +228,7 @@ class Insertion {
}

/**
* @private
* @param {module:engine/model/node~Node} node The disallowed node which needs to be handled.
* @param {Object} context
*/
Expand All @@ -241,6 +244,7 @@ class Insertion {
}

/**
* @private
* @param {module:engine/model/node~Node} node The node to insert.
*/
_insert( node ) {
Expand Down Expand Up @@ -274,6 +278,7 @@ class Insertion {
}

/**
* @private
* @param {module:engine/model/node~Node} node The node which could potentially be merged.
* @param {Object} context
*/
Expand All @@ -282,8 +287,8 @@ class Insertion {
return;
}

const mergeLeft = context.isFirst && ( node.previousSibling instanceof Element ) && this.canMergeWith.has( node.previousSibling );
const mergeRight = context.isLast && ( node.nextSibling instanceof Element ) && this.canMergeWith.has( node.nextSibling );
const mergeLeft = this._canMergeLeft( node, context );
const mergeRight = this._canMergeRight( node, context );
const mergePosLeft = LivePosition.createBefore( node );
const mergePosRight = LivePosition.createAfter( node );

Expand Down Expand Up @@ -329,9 +334,44 @@ class Insertion {
mergePosRight.detach();
}

/**
* Checks whether specified node can be merged with previous sibling element.
*
* @private
* @param {module:engine/model/node~Node} node The node which could potentially be merged.
* @param {Object} context
* @returns {Boolean}
*/
_canMergeLeft( node, context ) {
const previousSibling = node.previousSibling;

return context.isFirst &&
( previousSibling instanceof Element ) &&
this.canMergeWith.has( previousSibling ) &&
this.model.schema.checkMerge( previousSibling, node );
}

/**
* Checks whether specified node can be merged with next sibling element.
*
* @private
* @param {module:engine/model/node~Node} node The node which could potentially be merged.
* @param {Object} context
* @returns {Boolean}
*/
_canMergeRight( node, context ) {
const nextSibling = node.nextSibling;

return context.isLast &&
( nextSibling instanceof Element ) &&
this.canMergeWith.has( nextSibling ) &&
this.model.schema.checkMerge( node, nextSibling );
}

/**
* Tries wrapping the node in a new paragraph and inserting it this way.
*
* @private
* @param {module:engine/model/node~Node} node The node which needs to be autoparagraphed.
* @param {Object} context
*/
Expand All @@ -348,6 +388,7 @@ class Insertion {
}

/**
* @private
* @param {module:engine/model/node~Node} node
* @returns {Boolean} Whether an allowed position was found.
* `false` is returned if the node isn't allowed at any position up in the tree, `true` if was.
Expand Down Expand Up @@ -393,6 +434,7 @@ class Insertion {
/**
* Gets the element in which the given node is allowed. It checks the passed element and all its ancestors.
*
* @private
* @param {module:engine/model/node~Node} node The node to check.
* @param {module:engine/model/element~Element} element The element in which the node's correctness should be checked.
* @returns {module:engine/model/element~Element|null}
Expand Down
57 changes: 57 additions & 0 deletions tests/model/utils/insertcontent.js
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,63 @@ describe( 'DataController utils', () => {
'<paragraph>b</paragraph>'
);
} );

it( 'should not merge a paragraph wrapped in blockQuote with list item (checking left merge)', () => {
model.schema.register( 'blockQuote', {
allowWhere: '$block',
allowContentOf: '$root',
} );

setData( model, '<listItem>fo[]o</listItem>' );

insertHelper( '<blockQuote><paragraph>xxx</paragraph></blockQuote><heading1>yyy</heading1>' );

expect( getData( model ) ).to.equal(
'<listItem>fo</listItem>' +
'<blockQuote>' +
'<paragraph>xxx</paragraph>' +
'</blockQuote>' +
'<heading1>yyy[]o</heading1>'
);
} );

it( 'should not merge a paragraph wrapped in blockQuote with list item (checking right merge)', () => {
model.schema.register( 'blockQuote', {
allowWhere: '$block',
allowContentOf: '$root',
} );

setData( model, '<listItem>fo[]o</listItem>' );

insertHelper( '<heading1>yyy</heading1><blockQuote><paragraph>xxx</paragraph></blockQuote>' );

expect( getData( model ) ).to.equal(
'<listItem>foyyy</listItem>' +
'<blockQuote>' +
'<paragraph>xxx</paragraph>' +
'</blockQuote>' +
'<listItem>[]o</listItem>'
);
} );

it( 'should not merge a paragraph wrapped in blockQuote with list item (checking both merges)', () => {
model.schema.register( 'blockQuote', {
allowWhere: '$block',
allowContentOf: '$root',
} );

setData( model, '<listItem>fo[]o</listItem>' );

insertHelper( '<blockQuote><paragraph>xxx</paragraph></blockQuote>' );

expect( getData( model ) ).to.equal(
'<listItem>fo</listItem>' +
'<blockQuote>' +
'<paragraph>xxx</paragraph>' +
'</blockQuote>' +
'<listItem>[]o</listItem>'
);
} );
} );

describe( 'mixed content to block', () => {
Expand Down

0 comments on commit 2a73830

Please sign in to comment.