Przeglądaj źródła

Option to ignore markers in Model#hasContent().

Kuba Niegowski 5 lat temu
rodzic
commit
ea4e36a0d4

+ 8 - 5
packages/ckeditor5-engine/src/model/model.js

@@ -551,6 +551,7 @@ export default class Model {
 	 * @param {module:engine/model/range~Range|module:engine/model/element~Element} rangeOrElement Range or element to check.
 	 * @param {Object} [options]
 	 * @param {Boolean} [options.ignoreWhitespaces] Whether text node with whitespaces only should be considered empty.
+	 * @param {Boolean} [options.ignoreMarkers] Whether markers should be ignored.
 	 * @returns {Boolean}
 	 */
 	hasContent( rangeOrElement, options ) {
@@ -560,15 +561,17 @@ export default class Model {
 			return false;
 		}
 
+		const { ignoreWhitespaces = false, ignoreMarkers = false } = options || {};
+
 		// Check if there are any markers which affects data in this given range.
-		for ( const intersectingMarker of this.markers.getMarkersIntersectingRange( range ) ) {
-			if ( intersectingMarker.affectsData ) {
-				return true;
+		if ( !ignoreMarkers ) {
+			for ( const intersectingMarker of this.markers.getMarkersIntersectingRange( range ) ) {
+				if ( intersectingMarker.affectsData ) {
+					return true;
+				}
 			}
 		}
 
-		const { ignoreWhitespaces = false } = options || {};
-
 		for ( const item of range.getItems() ) {
 			if ( item.is( 'textProxy' ) ) {
 				if ( !ignoreWhitespaces ) {

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

@@ -137,7 +137,7 @@ function getLivePositionsForSelectedBlocks( range ) {
 
 	// If the end of selection is at the start position of last block in the selection, then
 	// shrink it to not include that trailing block. Note that this should happen only for not empty selection.
-	if ( model.hasContent( range ) ) {
+	if ( model.hasContent( range, { ignoreMarkers: true } ) ) {
 		const endBlock = getParentBlock( endPosition );
 
 		if ( endBlock && endPosition.isTouching( model.createPositionAt( endBlock, 0 ) ) ) {
@@ -213,7 +213,7 @@ function mergeBranches( writer, startPosition, endPosition ) {
 	// Merging should not go deeper than common ancestor.
 	const [ startAncestor, endAncestor ] = getAncestorsJustBelowCommonAncestor( startPosition, endPosition );
 
-	if ( !model.hasContent( startAncestor ) && model.hasContent( endAncestor ) ) {
+	if ( !model.hasContent( startAncestor, { ignoreMarkers: true } ) && model.hasContent( endAncestor, { ignoreMarkers: true } ) ) {
 		mergeBranchesRight( writer, startPosition, endPosition, startAncestor.parent );
 	} else {
 		mergeBranchesLeft( writer, startPosition, endPosition, startAncestor.parent );

+ 13 - 0
packages/ckeditor5-engine/tests/model/model.js

@@ -659,6 +659,8 @@ describe( 'Model', () => {
 
 			expect( model.hasContent( pEmpty ) ).to.be.false;
 			expect( model.hasContent( pEmpty, { ignoreWhitespaces: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true, ignoreWhitespaces: true } ) ).to.be.false;
 		} );
 
 		it( 'should return false for empty element with marker (usingOperation=true, affectsData=false)', () => {
@@ -672,6 +674,8 @@ describe( 'Model', () => {
 
 			expect( model.hasContent( pEmpty ) ).to.be.false;
 			expect( model.hasContent( pEmpty, { ignoreWhitespaces: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true, ignoreWhitespaces: true } ) ).to.be.false;
 		} );
 
 		it( 'should return false (ignoreWhitespaces) for empty text with marker (usingOperation=false, affectsData=false)', () => {
@@ -688,6 +692,7 @@ describe( 'Model', () => {
 			} );
 
 			expect( model.hasContent( pEmpty, { ignoreWhitespaces: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreWhitespaces: true, ignoreMarkers: true } ) ).to.be.false;
 		} );
 
 		it( 'should return true for empty text with marker (usingOperation=false, affectsData=false)', () => {
@@ -704,6 +709,8 @@ describe( 'Model', () => {
 			} );
 
 			expect( model.hasContent( pEmpty ) ).to.be.true;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true } ) ).to.be.true;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true, ignoreWhitespaces: true } ) ).to.be.false;
 		} );
 
 		it( 'should return false for empty element with marker (usingOperation=false, affectsData=true)', () => {
@@ -717,6 +724,8 @@ describe( 'Model', () => {
 
 			expect( model.hasContent( pEmpty ) ).to.be.false;
 			expect( model.hasContent( pEmpty, { ignoreWhitespaces: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true, ignoreWhitespaces: true } ) ).to.be.false;
 		} );
 
 		it( 'should return false for empty element with marker (usingOperation=true, affectsData=true)', () => {
@@ -730,6 +739,8 @@ describe( 'Model', () => {
 
 			expect( model.hasContent( pEmpty ) ).to.be.false;
 			expect( model.hasContent( pEmpty, { ignoreWhitespaces: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true } ) ).to.be.false;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true, ignoreWhitespaces: true } ) ).to.be.false;
 		} );
 
 		it( 'should return true (ignoreWhitespaces) for empty text with marker (usingOperation=false, affectsData=true)', () => {
@@ -747,6 +758,8 @@ describe( 'Model', () => {
 
 			expect( model.hasContent( pEmpty ) ).to.be.true;
 			expect( model.hasContent( pEmpty, { ignoreWhitespaces: true } ) ).to.be.true;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true } ) ).to.be.true;
+			expect( model.hasContent( pEmpty, { ignoreMarkers: true, ignoreWhitespaces: true } ) ).to.be.false;
 		} );
 	} );
 

+ 53 - 0
packages/ckeditor5-engine/tests/model/utils/deletecontent.js

@@ -661,6 +661,59 @@ describe( 'DataController utils', () => {
 				);
 			} );
 
+			describe( 'with markers', () => {
+				it( 'should merge left if first element is not empty', () => {
+					setData( model, '<heading1>foo[</heading1><paragraph>]bar</paragraph>' );
+
+					model.enqueueChange( 'transparent', writer => {
+						const root = doc.getRoot( );
+						const range = writer.createRange(
+							writer.createPositionFromPath( root, [ 0, 3 ] ),
+							writer.createPositionFromPath( root, [ 1, 0 ] )
+						);
+						writer.addMarker( 'comment1', { range, usingOperation: true, affectsData: true } );
+					} );
+
+					deleteContent( model, doc.selection );
+
+					expect( getData( model ) ).to.equal( '<heading1>foo[]bar</heading1>' );
+				} );
+
+				it( 'should merge right if first element is empty', () => {
+					setData( model, '<heading1>[</heading1><paragraph>]bar</paragraph>' );
+
+					model.enqueueChange( 'transparent', writer => {
+						const root = doc.getRoot( );
+						const range = writer.createRange(
+							writer.createPositionFromPath( root, [ 0, 0 ] ),
+							writer.createPositionFromPath( root, [ 1, 0 ] )
+						);
+						writer.addMarker( 'comment1', { range, usingOperation: true, affectsData: true } );
+					} );
+
+					deleteContent( model, doc.selection );
+
+					expect( getData( model ) ).to.equal( '<paragraph>[]bar</paragraph>' );
+				} );
+
+				it( 'should merge left if last element is empty', () => {
+					setData( model, '<heading1>foo[</heading1><paragraph>]</paragraph>' );
+
+					model.enqueueChange( 'transparent', writer => {
+						const root = doc.getRoot( );
+						const range = writer.createRange(
+							writer.createPositionFromPath( root, [ 0, 3 ] ),
+							writer.createPositionFromPath( root, [ 1, 0 ] )
+						);
+						writer.addMarker( 'comment1', { range, usingOperation: true, affectsData: true } );
+					} );
+
+					deleteContent( model, doc.selection );
+
+					expect( getData( model ) ).to.equal( '<heading1>foo[]</heading1>' );
+				} );
+			} );
+
 			describe( 'filtering out', () => {
 				beforeEach( () => {
 					const schema = model.schema;