8
0
Piotrek Koszuliński 5 gadi atpakaļ
vecāks
revīzija
2d2654f5d5

+ 12 - 2
packages/ckeditor5-engine/src/model/schema.js

@@ -672,12 +672,22 @@ export default class Schema {
 
 		let backwardWalker, forwardWalker;
 
+		// Never leave a limit element.
+		const limitElement = position.getAncestors().reverse().find( item => this.isLimit( item ) ) || position.root;
+
 		if ( direction == 'both' || direction == 'backward' ) {
-			backwardWalker = new TreeWalker( { startPosition: position, direction: 'backward' } );
+			backwardWalker = new TreeWalker( {
+				boundaries: Range._createIn( limitElement ),
+				startPosition: position,
+				direction: 'backward'
+			} );
 		}
 
 		if ( direction == 'both' || direction == 'forward' ) {
-			forwardWalker = new TreeWalker( { startPosition: position } );
+			forwardWalker = new TreeWalker( {
+				boundaries: Range._createIn( limitElement ),
+				startPosition: position
+			} );
 		}
 
 		for ( const data of combineWalkers( backwardWalker, forwardWalker ) ) {

+ 2 - 2
packages/ckeditor5-engine/src/model/utils/deletecontent.js

@@ -109,12 +109,12 @@ export default function deleteContent( model, selection, options = {} ) {
 
 		// 4. Add a paragraph to set selection in it.
 		// Check if a text is allowed in the new container. If not, try to create a new paragraph (if it's allowed here).
-		if ( shouldAutoparagraph( schema, startPos ) ) {
+		if ( !options.doNotAutoparagraph && shouldAutoparagraph( schema, startPos ) ) {
 			// If auto-paragraphing is off, find the closest valid selection range and collapse the selection there.
 			// If there is no valid selection range, create paragraph anyway and set selection there.
 			const validSelectionRange = schema.getNearestSelectionRange( startPos );
 
-			if ( options.doNotAutoparagraph && validSelectionRange ) {
+			if ( validSelectionRange ) {
 				collapseSelectionAt( writer, selection, validSelectionRange );
 			} else {
 				insertParagraph( writer, startPos, selection );

+ 2 - 4
packages/ckeditor5-engine/src/model/utils/insertcontent.js

@@ -50,13 +50,11 @@ export default function insertContent( model, content, selectable, placeOrOffset
 			selection = writer.createSelection( selectable, placeOrOffset );
 		}
 
-		const insertionPosition = selection.getFirstPosition();
-
 		if ( !selection.isCollapsed ) {
 			model.deleteContent( selection, { doNotAutoparagraph: true } );
 		}
 
-		const insertion = new Insertion( model, writer, insertionPosition );
+		const insertion = new Insertion( model, writer, selection.anchor );
 
 		let nodesToInsert;
 
@@ -89,7 +87,7 @@ export default function insertContent( model, content, selectable, placeOrOffset
 			// @if CK_DEBUG // console.warn( 'Cannot determine a proper selection range after insertion.' );
 		}
 
-		const affectedRange = insertion.getAffectedRange() || model.createRange( insertionPosition );
+		const affectedRange = insertion.getAffectedRange() || model.createRange( selection.anchor );
 
 		insertion.destroy();
 

+ 50 - 0
packages/ckeditor5-engine/tests/model/schema.js

@@ -1420,12 +1420,20 @@ describe( 'Schema', () => {
 				isObject: true
 			} );
 
+			// Similar to the <caption> case.
 			model.schema.register( 'blockWidget', {
 				allowIn: '$root',
 				allowContentOf: '$block',
 				isObject: true
 			} );
 
+			// Similar to the <tableCell> case.
+			model.schema.register( 'blockContainerWidget', {
+				allowIn: '$root',
+				allowContentOf: '$root',
+				isObject: true
+			} );
+
 			doc.createRoot();
 			selection = doc.selection;
 		} );
@@ -1622,6 +1630,48 @@ describe( 'Schema', () => {
 			);
 		} );
 
+		describe( 'in case of other types of objects', () => {
+			test(
+				'should return null when cannot leave a limit element',
+				'<blockContainerWidget>[]</blockContainerWidget>',
+				'both',
+				null
+			);
+
+			test(
+				'should return null when cannot leave a limit element (surrounded with paragraphs)',
+				'<paragraph>x</paragraph><blockContainerWidget>[]</blockContainerWidget><paragraph>x</paragraph>',
+				'both',
+				null
+			);
+
+			test(
+				'should return null when cannot leave a limit element (surrounded by other widgets)',
+
+				'<blockContainerWidget><paragraph>x</paragraph></blockContainerWidget>' +
+				'<blockContainerWidget>[]</blockContainerWidget>' +
+				'<blockContainerWidget><paragraph>x</paragraph></blockContainerWidget>',
+
+				'both',
+
+				null
+			);
+
+			test(
+				'should keep scanning even though encountering a limit in one direction (left)',
+				'<paragraph>x</paragraph><blockContainerWidget>[]<paragraph>x</paragraph></blockContainerWidget><paragraph>x</paragraph>',
+				'both',
+				'<paragraph>x</paragraph><blockContainerWidget><paragraph>[]x</paragraph></blockContainerWidget><paragraph>x</paragraph>'
+			);
+
+			test(
+				'should keep scanning even though encountering a limit in one direction (right)',
+				'<paragraph>x</paragraph><blockContainerWidget><paragraph>x</paragraph>[]</blockContainerWidget><paragraph>x</paragraph>',
+				'both',
+				'<paragraph>x</paragraph><blockContainerWidget><paragraph>x[]</paragraph></blockContainerWidget><paragraph>x</paragraph>'
+			);
+		} );
+
 		function test( testName, data, direction, expected ) {
 			it( testName, () => {
 				let range;