Преглед изворни кода

Added ablity to change marker type at runtime.

Maciej Bukowski пре 8 година
родитељ
комит
566764cfce

+ 1 - 9
packages/ckeditor5-engine/src/model/markercollection.js

@@ -111,15 +111,7 @@ export default class MarkerCollection {
 		if ( oldMarker ) {
 			const oldRange = oldMarker.getRange();
 
-			if ( managedUsingOperations !== oldMarker.managedUsingOperations ) {
-				/**
-				 * Marker's type should be consistent. Provide correct `managedUsingOperations` parameter.
-				 */
-				throw new CKEditorError( 'marker-set-incorrect-marker-type:' +
-				' Marker\'s type should be consistent. Provide correct `managedUsingOperations` parameter.' );
-			}
-
-			if ( oldRange.isEqual( range ) ) {
+			if ( oldRange.isEqual( range ) && managedUsingOperations === oldMarker.managedUsingOperations ) {
 				return oldMarker;
 			}
 

+ 8 - 2
packages/ckeditor5-engine/src/model/writer.js

@@ -836,6 +836,8 @@ export default class Writer {
 			}
 		}
 
+		const currentMarker = this.model.markers.get( markerName );
+
 		if ( !usingOperation ) {
 			if ( !newRange ) {
 				/**
@@ -846,11 +848,15 @@ export default class Writer {
 				throw new CKEditorError( 'writer-setMarker-no-range: Range parameter is required when adding a new marker.' );
 			}
 
+			// If marker changes to marker that do not use operations then we need to create additional operation
+			// that removes that marker first.
+			if ( currentMarker && currentMarker.managedUsingOperations && !usingOperation ) {
+				applyMarkerOperation( this, markerName, currentMarker.getRange(), null );
+			}
+
 			return this.model.markers._set( markerName, newRange, usingOperation );
 		}
 
-		const currentMarker = this.model.markers.get( markerName );
-
 		if ( !newRange && !currentMarker ) {
 			throw new CKEditorError( 'writer-setMarker-no-range: Range parameter is required when adding a new marker.' );
 		}

+ 31 - 4
packages/ckeditor5-engine/tests/model/writer.js

@@ -2076,12 +2076,39 @@ describe( 'Writer', () => {
 			} ).to.throw( CKEditorError, /^writer-setMarker-no-range/ );
 		} );
 
-		it( 'should throw if marker is updated incorrectly', () => {
+		it( 'should create additional operation when marker type changes to not managed using operation', () => {
+			const spy = sinon.spy();
+			model.on( 'applyOperation', spy );
+
+			setMarker( 'name', range, { usingOperation: true } );
+			const marker = setMarker( 'name', range );
+			const op1 = batch.deltas[ 0 ].operations[ 0 ];
+			const op2 = batch.deltas[ 1 ].operations[ 0 ];
+
+			expect( spy.calledTwice ).to.be.true;
+			expect( spy.firstCall.args[ 1 ][ 0 ].type ).to.equal( 'marker' );
+			expect( spy.secondCall.args[ 1 ][ 0 ].type ).to.equal( 'marker' );
+
+			expect( op1.oldRange ).to.be.null;
+			expect( op1.newRange.isEqual( range ) ).to.be.true;
+
+			expect( op2.oldRange.isEqual( range ) ).to.be.true;
+			expect( op2.newRange ).to.be.null;
+
+			expect( marker.managedUsingOperations ).to.be.false;
+		} );
+
+		it( 'should enable changing marker to be not managed using operation', () => {
+			const spy = sinon.spy();
+			model.on( 'applyOperation', spy );
+
 			setMarker( 'name', range );
+			const marker = setMarker( 'name', range, { usingOperation: true } );
 
-			expect( () => {
-				setMarker( 'name', range, { usingOperation: true } );
-			} ).to.throw( CKEditorError, /^marker-set-incorrect-marker-type/ );
+			expect( spy.calledOnce ).to.be.true;
+			expect( spy.firstCall.args[ 1 ][ 0 ].type ).to.equal( 'marker' );
+
+			expect( marker.managedUsingOperations ).to.be.true;
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {