8
0
Просмотр исходного кода

Merge branch 'master' into t/1604

Szymon Cofalik 7 лет назад
Родитель
Сommit
80bd51a44a

+ 1 - 1
packages/ckeditor5-engine/docs/api/engine.md

@@ -12,7 +12,7 @@ Together with the {@link api/core core editor architecture} and the {@link api/u
 
 
 ## Documentation
 ## Documentation
 
 
-See the introduction to the {@link framework/guides/architecture/intro#editing-engine editing engine's architecture}.
+See the introduction to the {@link framework/guides/architecture/editing-engine editing engine's architecture}.
 
 
 You can also browse the API documentation of this package by using the module tree on the left.
 You can also browse the API documentation of this package by using the module tree on the left.
 
 

+ 1 - 1
packages/ckeditor5-engine/package.json

@@ -39,7 +39,7 @@
     "@ckeditor/ckeditor5-undo": "^10.0.4",
     "@ckeditor/ckeditor5-undo": "^10.0.4",
     "@ckeditor/ckeditor5-widget": "^10.3.1",
     "@ckeditor/ckeditor5-widget": "^10.3.1",
     "eslint": "^5.5.0",
     "eslint": "^5.5.0",
-    "eslint-config-ckeditor5": "^1.0.7",
+    "eslint-config-ckeditor5": "^1.0.9",
     "husky": "^0.14.3",
     "husky": "^0.14.3",
     "lint-staged": "^7.0.0"
     "lint-staged": "^7.0.0"
   },
   },

+ 2 - 1
packages/ckeditor5-engine/src/model/documentselection.js

@@ -696,7 +696,8 @@ class LiveSelection extends Selection {
 			 * UID obtained from the {@link module:engine/model/writer~Writer#overrideSelectionGravity} to restore.
 			 * UID obtained from the {@link module:engine/model/writer~Writer#overrideSelectionGravity} to restore.
 			 *
 			 *
 			 * @error document-selection-gravity-wrong-restore
 			 * @error document-selection-gravity-wrong-restore
-			 * @param {String} uid The unique identifier returned by {@link #overrideGravity}.
+			 * @param {String} uid The unique identifier returned by
+			 * {@link module:engine/model/documentselection~DocumentSelection#_overrideGravity}.
 			 */
 			 */
 			throw new CKEditorError(
 			throw new CKEditorError(
 				'document-selection-gravity-wrong-restore: Attempting to restore the selection gravity for an unknown UID.',
 				'document-selection-gravity-wrong-restore: Attempting to restore the selection gravity for an unknown UID.',

+ 47 - 18
packages/ckeditor5-engine/src/model/utils/selection-post-fixer.js

@@ -183,11 +183,19 @@ function tryFixingNonCollapsedRage( range, schema ) {
 		// - [<block>foo</block>]    ->    <block>[foo]</block>
 		// - [<block>foo</block>]    ->    <block>[foo]</block>
 		// - [<block>foo]</block>    ->    <block>[foo]</block>
 		// - [<block>foo]</block>    ->    <block>[foo]</block>
 		// - <block>f[oo</block>]    ->    <block>f[oo]</block>
 		// - <block>f[oo</block>]    ->    <block>f[oo]</block>
+		// - [<block>foo</block><object></object>]    ->    <block>[foo</block><object></object>]
 		if ( checkSelectionOnNonLimitElements( start, end, schema ) ) {
 		if ( checkSelectionOnNonLimitElements( start, end, schema ) ) {
-			const fixedStart = schema.getNearestSelectionRange( start, 'forward' );
-			const fixedEnd = schema.getNearestSelectionRange( end, 'backward' );
+			const isStartObject = start.nodeAfter && schema.isObject( start.nodeAfter );
+			const fixedStart = isStartObject ? null : schema.getNearestSelectionRange( start, 'forward' );
 
 
-			return new Range( fixedStart ? fixedStart.start : start, fixedEnd ? fixedEnd.start : end );
+			const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore );
+			const fixedEnd = isEndObject ? null : schema.getNearestSelectionRange( end, 'backward' );
+
+			// The schema.getNearestSelectionRange might return null - if that happens use original position.
+			const rangeStart = fixedStart ? fixedStart.start : start;
+			const rangeEnd = fixedEnd ? fixedEnd.start : end;
+
+			return new Range( rangeStart, rangeEnd );
 		}
 		}
 	}
 	}
 
 
@@ -197,13 +205,23 @@ function tryFixingNonCollapsedRage( range, schema ) {
 	// At this point we eliminated valid positions on text nodes so if one of range positions is placed inside a limit element
 	// At this point we eliminated valid positions on text nodes so if one of range positions is placed inside a limit element
 	// then the range crossed limit element boundaries and needs to be fixed.
 	// then the range crossed limit element boundaries and needs to be fixed.
 	if ( isStartInLimit || isEndInLimit ) {
 	if ( isStartInLimit || isEndInLimit ) {
+		const bothInSameParent = ( start.nodeAfter && end.nodeBefore ) && start.nodeAfter.parent === end.nodeBefore.parent;
+
+		const expandStart = isStartInLimit && ( !bothInSameParent || !isInObject( start.nodeAfter, schema ) );
+		const expandEnd = isEndInLimit && ( !bothInSameParent || !isInObject( end.nodeBefore, schema ) );
+
 		// Although we've already found limit element on start/end positions we must find the outer-most limit element.
 		// Although we've already found limit element on start/end positions we must find the outer-most limit element.
 		// as limit elements might be nested directly inside (ie table > tableRow > tableCell).
 		// as limit elements might be nested directly inside (ie table > tableRow > tableCell).
-		const startPosition = Position._createAt( startLimitElement, 0 );
-		const endPosition = Position._createAt( endLimitElement, 0 );
+		let fixedStart = start;
+		let fixedEnd = end;
+
+		if ( expandStart ) {
+			fixedStart = Position._createBefore( findOutermostLimitAncestor( startLimitElement, schema ) );
+		}
 
 
-		const fixedStart = isStartInLimit ? expandSelectionOnIsLimitNode( startPosition, schema, 'start' ) : start;
-		const fixedEnd = isEndInLimit ? expandSelectionOnIsLimitNode( endPosition, schema, 'end' ) : end;
+		if ( expandEnd ) {
+			fixedEnd = Position._createAfter( findOutermostLimitAncestor( endLimitElement, schema ) );
+		}
 
 
 		return new Range( fixedStart, fixedEnd );
 		return new Range( fixedStart, fixedEnd );
 	}
 	}
@@ -212,34 +230,45 @@ function tryFixingNonCollapsedRage( range, schema ) {
 	return null;
 	return null;
 }
 }
 
 
-// Expands selection so it contains whole limit node.
+// Finds the outer-most ancestor.
 //
 //
-// @param {module:engine/model/position~Position} position
+// @param {module:engine/model/node~Node} startingNode
 // @param {module:engine/model/schema~Schema} schema
 // @param {module:engine/model/schema~Schema} schema
 // @param {String} expandToDirection Direction of expansion - either 'start' or 'end' of the range.
 // @param {String} expandToDirection Direction of expansion - either 'start' or 'end' of the range.
-// @returns {module:engine/model/position~Position}
-function expandSelectionOnIsLimitNode( position, schema, expandToDirection ) {
-	let node = position.parent;
-	let parent = node;
+// @returns {module:engine/model/node~Node}
+function findOutermostLimitAncestor( startingNode, schema ) {
+	let isLimitNode = startingNode;
+	let parent = isLimitNode;
 
 
 	// Find outer most isLimit block as such blocks might be nested (ie. in tables).
 	// Find outer most isLimit block as such blocks might be nested (ie. in tables).
 	while ( schema.isLimit( parent ) && parent.parent ) {
 	while ( schema.isLimit( parent ) && parent.parent ) {
-		node = parent;
+		isLimitNode = parent;
 		parent = parent.parent;
 		parent = parent.parent;
 	}
 	}
 
 
-	// Depending on direction of expanding selection return position before or after found node.
-	return expandToDirection === 'start' ? Position._createBefore( node ) : Position._createAfter( node );
+	return isLimitNode;
 }
 }
 
 
-// Checks whether both range ends are placed around non-limit elements.
+// Checks whether any of range boundaries is placed around non-limit elements.
 //
 //
 // @param {module:engine/model/position~Position} start
 // @param {module:engine/model/position~Position} start
 // @param {module:engine/model/position~Position} end
 // @param {module:engine/model/position~Position} end
 // @param {module:engine/model/schema~Schema} schema
 // @param {module:engine/model/schema~Schema} schema
+// @returns {Boolean}
 function checkSelectionOnNonLimitElements( start, end, schema ) {
 function checkSelectionOnNonLimitElements( start, end, schema ) {
 	const startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' );
 	const startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' );
 	const endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' );
 	const endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' );
 
 
-	return startIsOnBlock && endIsOnBlock;
+	// We should fix such selection when one of those nodes needs fixing.
+	return startIsOnBlock || endIsOnBlock;
+}
+
+// Checks if node exists and if it's an object.
+//
+// @param {module:engine/model/node~Node} node
+// @param {module:engine/model/schema~Schema} schema
+// @returns {Boolean}
+function isInObject( node, schema ) {
+	return node && schema.isObject( node );
 }
 }
+

+ 284 - 44
packages/ckeditor5-engine/tests/model/utils/selection-post-fixer.js

@@ -27,8 +27,9 @@ describe( 'Selection post-fixer', () => {
 
 
 			model.schema.register( 'table', {
 			model.schema.register( 'table', {
 				allowWhere: '$block',
 				allowWhere: '$block',
-				isObject: true,
-				isLimit: true
+				allowAttributes: [ 'headingRows', 'headingColumns' ],
+				isLimit: true,
+				isObject: true
 			} );
 			} );
 
 
 			model.schema.register( 'tableRow', {
 			model.schema.register( 'tableRow', {
@@ -38,15 +39,18 @@ describe( 'Selection post-fixer', () => {
 
 
 			model.schema.register( 'tableCell', {
 			model.schema.register( 'tableCell', {
 				allowIn: 'tableRow',
 				allowIn: 'tableRow',
-				allowContentOf: '$block',
+				allowAttributes: [ 'colspan', 'rowspan' ],
 				isLimit: true
 				isLimit: true
 			} );
 			} );
 
 
 			model.schema.register( 'image', {
 			model.schema.register( 'image', {
-				allowIn: '$root',
-				isObject: true
+				isObject: true,
+				isBlock: true,
+				allowWhere: '$block'
 			} );
 			} );
 
 
+			model.schema.extend( '$block', { allowIn: 'tableCell' } );
+
 			model.schema.register( 'caption', {
 			model.schema.register( 'caption', {
 				allowIn: 'image',
 				allowIn: 'image',
 				allowContentOf: '$block',
 				allowContentOf: '$block',
@@ -98,13 +102,16 @@ describe( 'Selection post-fixer', () => {
 				setModelData( model,
 				setModelData( model,
 					'<paragraph>[]foo</paragraph>' +
 					'<paragraph>[]foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);
 			} );
 			} );
 
 
-			it( 'should fix #1', () => {
+			it( 'should fix #1 - range start outside table, end on table cell', () => {
 				// <paragraph>f[oo</paragraph><table><tableRow><tableCell></tableCell>]<tableCell>...
 				// <paragraph>f[oo</paragraph><table><tableRow><tableCell></tableCell>]<tableCell>...
 				model.change( writer => {
 				model.change( writer => {
 					writer.setSelection( writer.createRange(
 					writer.setSelection( writer.createRange(
@@ -116,13 +123,16 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>f[oo</paragraph>' +
 					'<paragraph>f[oo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>]' +
 					'</table>]' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);
 			} );
 			} );
 
 
-			it( 'should fix #2', () => {
+			it( 'should fix #2 - range start on table cell, end outside table', () => {
 				// ...<table><tableRow><tableCell></tableCell>[<tableCell></tableCell></tableRow></table><paragraph>b]ar</paragraph>
 				// ...<table><tableRow><tableCell></tableCell>[<tableCell></tableCell></tableRow></table><paragraph>b]ar</paragraph>
 				model.change( writer => {
 				model.change( writer => {
 					writer.setSelection( writer.createRange(
 					writer.setSelection( writer.createRange(
@@ -134,7 +144,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'[<table>' +
 					'[<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>b]ar</paragraph>'
 					'<paragraph>b]ar</paragraph>'
 				);
 				);
@@ -152,7 +165,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>f[oo</paragraph>' +
 					'<paragraph>f[oo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>]' +
 					'</table>]' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);
@@ -162,15 +178,18 @@ describe( 'Selection post-fixer', () => {
 				// <paragraph>foo</paragraph><table><tableRow><tableCell>a[aa</tableCell><tableCell>b]bb</tableCell>
 				// <paragraph>foo</paragraph><table><tableRow><tableCell>a[aa</tableCell><tableCell>b]bb</tableCell>
 				model.change( writer => {
 				model.change( writer => {
 					writer.setSelection( writer.createRange(
 					writer.setSelection( writer.createRange(
-						writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ).getChild( 0 ), 1 ),
-						writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ).getChild( 1 ), 2 )
+						writer.createPositionAt( modelRoot.getNodeByPath( [ 1, 0, 0, 0 ] ), 1 ),
+						writer.createPositionAt( modelRoot.getNodeByPath( [ 1, 0, 1, 0 ] ), 2 )
 					) );
 					) );
 				} );
 				} );
 
 
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'[<table>' +
 					'[<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>]' +
 					'</table>]' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);
@@ -180,11 +199,17 @@ describe( 'Selection post-fixer', () => {
 				setModelData( model,
 				setModelData( model,
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'[]' +
 					'[]' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>xxx</tableCell><tableCell>yyy</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>xxx</paragraph></tableCell>' +
+							'<tableCell><paragraph>yyy</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>baz</paragraph>'
 					'<paragraph>baz</paragraph>'
 				);
 				);
@@ -192,10 +217,16 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'[<table>' +
 					'[<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>]' +
 					'</table>]' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>xxx</tableCell><tableCell>yyy</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>xxx</paragraph></tableCell>' +
+							'<tableCell><paragraph>yyy</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>baz</paragraph>'
 					'<paragraph>baz</paragraph>'
 				);
 				);
@@ -208,7 +239,10 @@ describe( 'Selection post-fixer', () => {
 				setModelData( model,
 				setModelData( model,
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'[<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>]' +
+						'[<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>]' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>baz</paragraph>'
 					'<paragraph>baz</paragraph>'
 				);
 				);
@@ -216,7 +250,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'[<table>' +
 					'[<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>]' +
 					'</table>]' +
 					'<paragraph>baz</paragraph>'
 					'<paragraph>baz</paragraph>'
 				);
 				);
@@ -226,9 +263,18 @@ describe( 'Selection post-fixer', () => {
 				setModelData( model,
 				setModelData( model,
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'[<tableRow><tableCell>1</tableCell><tableCell>2</tableCell></tableRow>' +
-						'<tableRow><tableCell>3</tableCell><tableCell>4</tableCell>]</tableRow>' +
-						'<tableRow><tableCell>5</tableCell><tableCell>6</tableCell></tableRow>' +
+						'[<tableRow>' +
+							'<tableCell><paragraph>1</paragraph></tableCell>' +
+							'<tableCell><paragraph>2</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>3</paragraph></tableCell>' +
+							'<tableCell><paragraph>4</paragraph></tableCell>]' +
+						'</tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>5</paragraph></tableCell>' +
+							'<tableCell><paragraph>6</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>baz</paragraph>'
 					'<paragraph>baz</paragraph>'
 				);
 				);
@@ -236,9 +282,18 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'[<table>' +
 					'[<table>' +
-						'<tableRow><tableCell>1</tableCell><tableCell>2</tableCell></tableRow>' +
-						'<tableRow><tableCell>3</tableCell><tableCell>4</tableCell></tableRow>' +
-						'<tableRow><tableCell>5</tableCell><tableCell>6</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>1</paragraph></tableCell>' +
+							'<tableCell><paragraph>2</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>3</paragraph></tableCell>' +
+							'<tableCell><paragraph>4</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>5</paragraph></tableCell>' +
+							'<tableCell><paragraph>6</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>]' +
 					'</table>]' +
 					'<paragraph>baz</paragraph>'
 					'<paragraph>baz</paragraph>'
 				);
 				);
@@ -270,11 +325,14 @@ describe( 'Selection post-fixer', () => {
 				);
 				);
 			} );
 			} );
 
 
-			it( 'should not fix #1', () => {
+			it( 'should not fix #1 - selection over paragraphs outside table', () => {
 				setModelData( model,
 				setModelData( model,
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>b[ar</paragraph>' +
 					'<paragraph>b[ar</paragraph>' +
 					'<paragraph>ba]z</paragraph>'
 					'<paragraph>ba]z</paragraph>'
@@ -283,13 +341,133 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>b[ar</paragraph>' +
 					'<paragraph>b[ar</paragraph>' +
 					'<paragraph>ba]z</paragraph>'
 					'<paragraph>ba]z</paragraph>'
 				);
 				);
 			} );
 			} );
 
 
+			it( 'should not fix #2 - selection over image in table', () => {
+				setModelData( model,
+					'<paragraph>foo</paragraph>' +
+					'<table>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>foo</paragraph><image></image></tableCell>' +
+							'<tableCell><paragraph>[]bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+					'</table>'
+				);
+
+				model.change( writer => {
+					const image = model.document.getRoot().getNodeByPath( [ 1, 0, 0, 1 ] );
+
+					writer.setSelection( writer.createRangeOn( image ) );
+				} );
+
+				expect( getModelData( model ) ).to.equal(
+					'<paragraph>foo</paragraph>' +
+					'<table>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>foo</paragraph>[<image></image>]</tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+					'</table>'
+				);
+			} );
+
+			it( 'should not fix #3 - selection over paragraph & image in table', () => {
+				setModelData( model,
+					'<paragraph>foo</paragraph>' +
+					'<table>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>foo</paragraph><image></image></tableCell>' +
+							'<tableCell><paragraph>[]bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+					'</table>'
+				);
+
+				model.change( writer => {
+					const tableCell = model.document.getRoot().getNodeByPath( [ 1, 0, 0 ] );
+
+					writer.setSelection( writer.createRangeIn( tableCell ) );
+				} );
+
+				expect( getModelData( model ) ).to.equal(
+					'<paragraph>foo</paragraph>' +
+					'<table>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>[foo</paragraph><image></image>]</tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+					'</table>'
+				);
+			} );
+
+			it( 'should not fix #4 - selection over image & paragraph in table', () => {
+				setModelData( model,
+					'<paragraph>foo</paragraph>' +
+					'<table>' +
+						'<tableRow>' +
+							'<tableCell><image></image><paragraph>foo</paragraph></tableCell>' +
+							'<tableCell><paragraph>[]bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+					'</table>'
+				);
+
+				model.change( writer => {
+					const tableCell = model.document.getRoot().getNodeByPath( [ 1, 0, 0 ] );
+
+					writer.setSelection( writer.createRangeIn( tableCell ) );
+				} );
+
+				expect( getModelData( model ) ).to.equal(
+					'<paragraph>foo</paragraph>' +
+					'<table>' +
+						'<tableRow>' +
+							'<tableCell>[<image></image><paragraph>foo]</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+					'</table>'
+				);
+			} );
+
+			it( 'should not fix #5 - selection over blockQuote in table', () => {
+				model.schema.register( 'blockQuote', {
+					allowWhere: '$block',
+					allowContentOf: '$root'
+				} );
+
+				setModelData( model,
+					'<paragraph>foo</paragraph>' +
+					'<table>' +
+						'<tableRow>' +
+							'<tableCell><blockQuote><paragraph>foo</paragraph></blockQuote></tableCell>' +
+							'<tableCell><paragraph>[]bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+					'</table>'
+				);
+
+				model.change( writer => {
+					const tableCell = model.document.getRoot().getNodeByPath( [ 1, 0, 0 ] );
+
+					writer.setSelection( writer.createRangeIn( tableCell ) );
+				} );
+
+				expect( getModelData( model ) ).to.equal(
+					'<paragraph>foo</paragraph>' +
+					'<table>' +
+						'<tableRow>' +
+							'<tableCell><blockQuote><paragraph>[foo]</paragraph></blockQuote></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+					'</table>'
+				);
+			} );
+
 			it( 'should fix multiple ranges #1', () => {
 			it( 'should fix multiple ranges #1', () => {
 				model.change( writer => {
 				model.change( writer => {
 					const ranges = [
 					const ranges = [
@@ -308,7 +486,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>f[oo</paragraph>' +
 					'<paragraph>f[oo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>]' +
 					'</table>]' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);
@@ -333,7 +514,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>f[oo</paragraph>' +
 					'<paragraph>f[oo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>ba]r</paragraph>'
 					'<paragraph>ba]r</paragraph>'
 				);
 				);
@@ -343,10 +527,22 @@ describe( 'Selection post-fixer', () => {
 				setModelData( model,
 				setModelData( model,
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>[aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
-						'<tableRow>]<tableCell>[aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
-						'<tableRow>]<tableCell>[aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
-						'<tableRow>]<tableCell>[aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>[aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>]' +
+							'<tableCell><paragraph>[aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>]' +
+							'<tableCell><paragraph>[aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>]' +
+							'<tableCell><paragraph>[aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>b]az</paragraph>'
 					'<paragraph>b]az</paragraph>'
 				);
 				);
@@ -354,10 +550,22 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'[<table>' +
 					'[<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>b]az</paragraph>'
 					'<paragraph>b]az</paragraph>'
 				);
 				);
@@ -386,7 +594,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>f[oo</paragraph>' +
 					'<paragraph>f[oo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>bar]</paragraph>'
 					'<paragraph>bar]</paragraph>'
 				);
 				);
@@ -715,6 +926,23 @@ describe( 'Selection post-fixer', () => {
 					'<paragraph>fo[o<inlineWidget></inlineWidget>b]ar</paragraph>'
 					'<paragraph>fo[o<inlineWidget></inlineWidget>b]ar</paragraph>'
 				);
 				);
 			} );
 			} );
+
+			it( 'should not fix #4 - object in object', () => {
+				model.schema.register( 'div', {
+					allowIn: [ '$root', 'div' ],
+					isObject: true
+				} );
+
+				setModelData( model, '<div>[<div></div>]</div>' );
+
+				model.change( writer => {
+					const innerDiv = model.document.getRoot().getNodeByPath( [ 0, 0 ] );
+
+					writer.setSelection( writer.createRangeOn( innerDiv ) );
+				} );
+
+				expect( getModelData( model ) ).to.equal( '<div>[<div></div>]</div>' );
+			} );
 		} );
 		} );
 
 
 		describe( 'collapsed selection', () => {
 		describe( 'collapsed selection', () => {
@@ -722,7 +950,10 @@ describe( 'Selection post-fixer', () => {
 				setModelData( model,
 				setModelData( model,
 					'<paragraph>[]foo</paragraph>' +
 					'<paragraph>[]foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);
@@ -739,7 +970,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo[]</paragraph>' +
 					'<paragraph>foo[]</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);
@@ -758,7 +992,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>foo</paragraph>' +
 					'<paragraph>foo</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>[]aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>[]aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);
@@ -778,7 +1015,10 @@ describe( 'Selection post-fixer', () => {
 				expect( getModelData( model ) ).to.equal(
 				expect( getModelData( model ) ).to.equal(
 					'<paragraph>[foo]</paragraph>' +
 					'<paragraph>[foo]</paragraph>' +
 					'<table>' +
 					'<table>' +
-						'<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
+						'<tableRow>' +
+							'<tableCell><paragraph>aaa</paragraph></tableCell>' +
+							'<tableCell><paragraph>bbb</paragraph></tableCell>' +
+						'</tableRow>' +
 					'</table>' +
 					'</table>' +
 					'<paragraph>bar</paragraph>'
 					'<paragraph>bar</paragraph>'
 				);
 				);