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

Fixed failing tests after virtual selection implementation.

Szymon Kupś 8 лет назад
Родитель
Сommit
c5528565fd

+ 3 - 3
packages/ckeditor5-engine/src/conversion/buildmodelconverter.js

@@ -15,7 +15,7 @@ import {
 	removeUIElement,
 	wrapItem,
 	unwrapItem,
-	virtualSelectionConverter
+	markerToVirtualSelection
 } from './model-to-view-converters';
 
 import { convertSelectionAttribute, convertSelectionMarker } from './model-selection-to-view-converters';
@@ -250,8 +250,8 @@ class ModelConverterBuilder {
 		const priority = this._from.priority === null ? 'normal' : this._from.priority;
 
 		for ( const dispatcher of this._dispatchers ) {
-			dispatcher.on( 'addMarker:' + this._from.name, virtualSelectionConverter( selectionDescriptor ), { priority } );
-			dispatcher.on( 'removeMarker:' + this._from.name, virtualSelectionConverter( selectionDescriptor, false ), { priority } );
+			dispatcher.on( 'addMarker:' + this._from.name, markerToVirtualSelection( selectionDescriptor ), { priority } );
+			dispatcher.on( 'removeMarker:' + this._from.name, markerToVirtualSelection( selectionDescriptor ), { priority } );
 			dispatcher.on( 'selectionMarker:' + this._from.name, convertSelectionMarker( selectionDescriptor ), { priority } );
 		}
 	}

+ 4 - 0
packages/ckeditor5-engine/src/conversion/model-selection-to-view-converters.js

@@ -180,6 +180,10 @@ export function convertSelectionMarker( selectionDescriptor ) {
 			selectionDescriptor( data, consumable, conversionApi ) :
 			selectionDescriptor;
 
+		if ( !descriptor ) {
+			return;
+		}
+
 		const viewElement = virtualSelectionDescriptorToAttribute( descriptor );
 		const consumableName = 'selectionMarker:' + data.name;
 

+ 24 - 107
packages/ckeditor5-engine/src/conversion/model-to-view-converters.js

@@ -122,7 +122,7 @@ export function insertUIElement( elementCreator ) {
 			return;
 		}
 
-		if ( !consumable.consume( data.range, 'addMarker' ) ) {
+		if ( !consumable.consume( data.range, evt.name ) ) {
 			return;
 		}
 
@@ -326,105 +326,6 @@ export function unwrapItem( elementCreator ) {
 	};
 }
 
-/**
- * Function factory, creates a converter that wraps model range.
- *
- * In contrary to {@link module:engine/conversion/model-to-view-converters~wrapItem}, this converter's input is a
- * {@link module:engine/model/range~Range model range} (not changed model item). The model range is mapped
- * to {@link module:engine/view/range~Range view range} and then, view items within that view range are wrapped in a
- * {@link module:engine/view/attributeelement~AttributeElement view attribute element}. Note, that `elementCreator`
- * function of this converter takes different parameters that `elementCreator` of `wrapItem`.
- *
- * Let's assume following model and view. `{}` represents a range that is added as a marker with `searchResult` name.
- * The range represents a result of search `ab` string in the model document. The range has to be visualized in view.
- *
- *		[paragraph]              MODEL ====> VIEW        <p>
- *			|- {a                                         |- <span class="searchResult">
- *			|-  b}                                        |   |- ab
- *			|-  c                                         |- c
- *
- * The wrapping node depends on passed parameter. If {@link module:engine/view/attributeelement~AttributeElement} was passed, it
- * will be cloned and the copy will become the wrapping element. If `Function` is provided, it is passed all the parameters of the
- * {@link module:engine/conversion/modelconversiondispatcher~ModelConversionDispatcher#event:addMarker addMarker event}. It's expected
- * that the function returns a {@link module:engine/view/attributeelement~AttributeElement}. The result of the function will be the
- * wrapping element. When provided `Function` does not return element, then will be no conversion.
- *
- * The converter automatically consumes corresponding value from consumables list, stops the event (see
- * {@link module:engine/conversion/modelconversiondispatcher~ModelConversionDispatcher}).
- *
- *		modelDispatcher.on( 'addMarker:searchResult', wrapRange( new ViewAttributeElement( 'span', { class: 'searchResult' } ) ) );
- *
- * @param {module:engine/view/attributeelement~AttributeElement|Function} elementCreator View attribute element, or function returning
- * a view attribute element, which will be used for wrapping.
- * @returns {Function} Wrap range converter.
- */
-export function wrapRange( elementCreator ) {
-	return ( evt, data, consumable, conversionApi ) => {
-		const viewElement = ( elementCreator instanceof ViewElement ) ?
-			elementCreator.clone( true ) :
-			elementCreator( data, consumable, conversionApi );
-
-		if ( !viewElement ) {
-			return;
-		}
-
-		if ( !consumable.consume( data.range, 'addMarker' ) ) {
-			return;
-		}
-
-		const viewRange = conversionApi.mapper.toViewRange( data.range );
-		const flatViewRanges = viewWriter.breakViewRangePerContainer( viewRange );
-
-		for ( const range of flatViewRanges ) {
-			viewWriter.wrap( range, viewElement );
-		}
-	};
-}
-
-/**
- * Function factory, creates a converter that converts removing of a model marker to view attribute element.
- * This converter will unwrap view nodes from corresponding view range.
- *
- * The view element that will be unwrapped depends on passed parameter. If {@link module:engine/view/attributeelement~AttributeElement}
- * was passed, it will be used to look for similar element in the view for unwrapping. If `Function` is provided, it is passed all
- * the parameters of the
- * {@link module:engine/conversion/modelconversiondispatcher~ModelConversionDispatcher#event:removeMarker removeMarker event}.
- * It's expected that the function returns a {@link module:engine/view/attributeelement~AttributeElement}. The result of
- * the function will be used to look for similar element in the view for unwrapping.
- *
- * The converter automatically consumes corresponding value from consumables list, stops the event (see
- * {@link module:engine/conversion/modelconversiondispatcher~ModelConversionDispatcher}) and bind model and view elements.
- *
- *		modelDispatcher.on( 'removeMarker:searchResult', unwrapRange( new ViewAttributeElement( 'span', { class: 'searchResult' } ) ) );
- *
- * @see module:engine/conversion/model-to-view-converters~wrapRange
- * @param {module:engine/view/attributeelement~AttributeElement|Function} elementCreator View attribute element, or function returning
- * a view attribute element, which will be used for unwrapping.
- * @returns {Function} Unwrap range converter.
- */
-export function unwrapRange( elementCreator ) {
-	return ( evt, data, consumable, conversionApi ) => {
-		const viewElement = ( elementCreator instanceof ViewElement ) ?
-			elementCreator.clone( true ) :
-			elementCreator( data, consumable, conversionApi );
-
-		if ( !viewElement ) {
-			return;
-		}
-
-		if ( !consumable.consume( data.range, 'removeMarker' ) ) {
-			return;
-		}
-
-		const viewRange = conversionApi.mapper.toViewRange( data.range );
-		const flatViewRanges = viewWriter.breakViewRangePerContainer( viewRange );
-
-		for ( const range of flatViewRanges ) {
-			viewWriter.unwrap( range, viewElement );
-		}
-	};
-}
-
 /**
  * Function factory, creates a default model-to-view converter for node remove changes.
  *
@@ -480,13 +381,25 @@ export function remove() {
 	};
 }
 
-export function virtualSelectionConverter( selectionDescriptor, addMarker = true ) {
+export function markerToVirtualSelection( selectionDescriptor ) {
 	return ( evt, data, consumable, conversionApi ) =>	{
-		const modelItem = data.item;
 		const descriptor = typeof selectionDescriptor == 'function' ?
 			selectionDescriptor( data, consumable, conversionApi ) :
 			selectionDescriptor;
 
+		if ( !descriptor ) {
+			return;
+		}
+
+		const addMarker = evt.name.split( ':' )[ 0 ] == 'addMarker';
+		const modelItem = data.item;
+
+		// Return if model item is not present. This happens when whole marker conversion is fired before converting
+		// children of marker's range.
+		if ( !modelItem ) {
+			return;
+		}
+
 		if ( modelItem.is( 'textProxy' ) ) {
 			const viewElement = virtualSelectionDescriptorToAttribute( descriptor );
 			const converter = addMarker ? wrapItem( viewElement ) : unwrapItem( viewElement );
@@ -495,7 +408,7 @@ export function virtualSelectionConverter( selectionDescriptor, addMarker = true
 		}
 
 		if ( modelItem.is( 'element' ) ) {
-			const consumableType = eventNameToConsumableType( evt.name );
+			const consumableType = evt.name;
 			const viewElement = conversionApi.mapper.toViewElement( modelItem );
 
 			if ( !consumable.consume( modelItem, consumableType ) ) {
@@ -563,7 +476,7 @@ export function removeUIElement( elementCreator ) {
 			return;
 		}
 
-		if ( !consumable.consume( data.range, 'removeMarker' ) ) {
+		if ( !consumable.consume( data.range, evt.name ) ) {
 			return;
 		}
 
@@ -592,11 +505,15 @@ export function eventNameToConsumableType( evtName ) {
 }
 
 export function virtualSelectionDescriptorToAttribute( descriptor ) {
-	const attribute = new ViewAttributeElement( 'span', descriptor.attributes );
+	const attributeElement = new ViewAttributeElement( 'span', descriptor.attributes );
 
 	if ( descriptor.class ) {
-		attribute.addClass( descriptor.class );
+		attributeElement.addClass( descriptor.class );
+	}
+
+	if ( descriptor.priority ) {
+		attributeElement.priority = descriptor.priority;
 	}
 
-	return attribute;
+	return attributeElement;
 }

+ 30 - 2
packages/ckeditor5-engine/src/conversion/modelconversiondispatcher.js

@@ -399,8 +399,20 @@ export default class ModelConversionDispatcher {
 			return;
 		}
 
+		// In markers case, event name == consumable name.
+		const eventName = type + ':' + name;
+
+		// Fire event for whole marker. This can be used to convert whole marker to element.
+		const markerConsumable = this._createMarkerConsumable( eventName, range );
+		this.fire( eventName, { name, range }, markerConsumable, this.conversionApi );
+
+		// Return if whole marker was consumed - do not perform conversion of each node in marker's range.
+		if ( !markerConsumable.test( range, eventName ) ) {
+			return;
+		}
+
 		// Create consumable for each item in range.
-		const consumable = this._createConsumableForRange( range, type + ':' + name.split( ':' )[ 0 ] );
+		const consumable = this._createConsumableForRange( range, eventName );
 
 		// Create separate event for each node in the range.
 		for ( const value of range ) {
@@ -412,7 +424,7 @@ export default class ModelConversionDispatcher {
 				range: itemRange
 			};
 
-			this.fire( type + ':' + name, data, consumable, this.conversionApi );
+			this.fire( eventName, data, consumable, this.conversionApi );
 		}
 	}
 
@@ -483,6 +495,22 @@ export default class ModelConversionDispatcher {
 		return consumable;
 	}
 
+	/**
+	 * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} for adding or removing marker on given `range`.
+	 *
+	 * @private
+	 * @param {'addMarker'|'removeMarker'} type Change type.
+	 * @param {module:engine/model/range~Range} range Range on which marker was added or removed.
+	 * @returns {module:engine/conversion/modelconsumable~ModelConsumable} Values to consume.
+	 */
+	_createMarkerConsumable( type, range ) {
+		const consumable = new Consumable();
+
+		consumable.add( range, type );
+
+		return consumable;
+	}
+
 	/**
 	 * Tests passed `consumable` to check whether given event can be fired and if so, fires it.
 	 *

+ 29 - 35
packages/ckeditor5-engine/tests/conversion/buildmodelconverter.js

@@ -343,7 +343,7 @@ describe( 'Model converter builder', () => {
 		} );
 	} );
 
-	describe( 'model marker to view element conversion', () => {
+	describe( 'model marker to virtual selection converter', () => {
 		let modelText, modelElement;
 
 		beforeEach( () => {
@@ -358,12 +358,23 @@ describe( 'Model converter builder', () => {
 			mapper.bindElements( modelElement, viewElement );
 		} );
 
-		it( 'using passed view element name', () => {
-			buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toElement( 'strong' );
+		it( 'using passed virtual selection descriptor object', () => {
+			buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toVirtualSelection( {
+				class: 'virtual-selection',
+				priority: 1,
+				attributes: { title: 'marker' }
+			} );
 
 			dispatcher.convertMarker( 'addMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 ) );
 
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<strong>ob</strong>ar</p></div>' );
+			expect( viewToString( viewRoot ) ).to.equal(
+				'<div>' +
+					'<p>' +
+						'fo' +
+						'<span class="virtual-selection" title="marker">ob</span>' +
+						'ar' +
+					'</p>' +
+				'</div>' );
 
 			dispatcher.convertMarker(
 				'removeMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 )
@@ -372,13 +383,23 @@ describe( 'Model converter builder', () => {
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
 		} );
 
-		it( 'using passed view element', () => {
-			const viewElement = new ViewAttributeElement( 'span', { class: 'search' } );
-			buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toElement( viewElement );
+		it( 'using passed virtual selection descriptor object creator', () => {
+			buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toVirtualSelection( () => ( {
+				class: 'virtual-selection',
+				priority: 12,
+				attributes: { title: 'marker' }
+			} ) );
 
 			dispatcher.convertMarker( 'addMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 ) );
 
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="search">ob</span>ar</p></div>' );
+			expect( viewToString( viewRoot ) ).to.equal(
+				'<div>' +
+					'<p>' +
+						'fo' +
+						'<span class="virtual-selection" title="marker">ob</span>' +
+						'ar' +
+					'</p>' +
+				'</div>' );
 
 			dispatcher.convertMarker(
 				'removeMarker', 'search', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 )
@@ -387,33 +408,6 @@ describe( 'Model converter builder', () => {
 			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
 		} );
 
-		it( 'using passed creator function', () => {
-			buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toElement( data => {
-				const className = 'search search-color-' + data.name.split( ':' )[ 1 ];
-
-				return new ViewAttributeElement( 'span', { class: className } );
-			} );
-
-			dispatcher.convertMarker(
-				'addMarker', 'search:red', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 )
-			);
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="search search-color-red">ob</span>ar</p></div>' );
-
-			dispatcher.convertMarker(
-				'removeMarker', 'search:blue', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 )
-			);
-
-			// Nothing should change as we remove a marker with different name, which should generate different view attribute element.
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="search search-color-red">ob</span>ar</p></div>' );
-
-			dispatcher.convertMarker(
-				'removeMarker', 'search:red', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 )
-			);
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
-
 		it( 'should do nothing when marker range is collapsed', () => {
 			buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toElement( 'strong' );
 

+ 13 - 13
packages/ckeditor5-engine/tests/conversion/model-selection-to-view-converters.js

@@ -28,15 +28,13 @@ import {
 	insertElement,
 	insertText,
 	wrapItem,
-	wrapRange,
-	unwrapRange
+	markerToVirtualSelection
 } from '../../src/conversion/model-to-view-converters';
 
 import { stringify as stringifyView } from '../../src/dev-utils/view';
 import { setData as setModelData } from '../../src/dev-utils/model';
 
-const spanViewElementForMarker = new ViewAttributeElement( 'span' );
-spanViewElementForMarker.priority = 1;
+const virtualSelectionDescriptor = { class: 'marker', priority: 1 };
 
 describe( 'model-selection-to-view-converters', () => {
 	let dispatcher, mapper, modelDoc, modelRoot, modelSelection, viewDoc, viewRoot, viewSelection;
@@ -59,8 +57,9 @@ describe( 'model-selection-to-view-converters', () => {
 
 		dispatcher.on( 'insert:$text', insertText() );
 		dispatcher.on( 'addAttribute:bold', wrapItem( new ViewAttributeElement( 'strong' ) ) );
-		dispatcher.on( 'addMarker:marker', wrapRange( spanViewElementForMarker ) );
-		dispatcher.on( 'removeMarker:marker', unwrapRange( spanViewElementForMarker ) );
+
+		dispatcher.on( 'addMarker:marker', markerToVirtualSelection( virtualSelectionDescriptor ) );
+		dispatcher.on( 'removeMarker:marker', markerToVirtualSelection( virtualSelectionDescriptor ) );
 
 		// Default selection converters.
 		dispatcher.on( 'selection', clearAttributes(), { priority: 'low' } );
@@ -77,7 +76,7 @@ describe( 'model-selection-to-view-converters', () => {
 			// Selection converters for selection attributes.
 			dispatcher.on( 'selectionAttribute:bold', convertSelectionAttribute( new ViewAttributeElement( 'strong' ) ) );
 			dispatcher.on( 'selectionAttribute:italic', convertSelectionAttribute( new ViewAttributeElement( 'em' ) ) );
-			dispatcher.on( 'selectionMarker:marker', convertSelectionMarker( spanViewElementForMarker ) );
+			dispatcher.on( 'selectionMarker:marker', convertSelectionMarker( virtualSelectionDescriptor ) );
 		} );
 
 		describe( 'range selection', () => {
@@ -229,13 +228,14 @@ describe( 'model-selection-to-view-converters', () => {
 				// Convert model to view.
 				dispatcher.convertInsertion( ModelRange.createIn( modelRoot ) );
 				dispatcher.convertMarker( 'addMarker', marker.name, marker.getRange() );
-
+                //
 				const markers = Array.from( modelDoc.markers.getMarkersAtPosition( modelSelection.getFirstPosition() ) );
 				dispatcher.convertSelection( modelSelection, markers );
 
 				// Stringify view and check if it is same as expected.
-				expect( stringifyView( viewRoot, viewSelection, { showType: false } ) )
-					.to.equal( '<div>f<span>o<strong>o{}b</strong>a</span>r</div>' );
+				expect( stringifyView( viewRoot, viewSelection, { showType: false } ) ).to.equal(
+					'<div>f<span class="marker">o<strong>o{}b</strong>a</span>r</div>'
+				);
 			} );
 
 			it( 'in attribute and marker - no attribute', () => {
@@ -261,12 +261,12 @@ describe( 'model-selection-to-view-converters', () => {
 
 				// Stringify view and check if it is same as expected.
 				expect( stringifyView( viewRoot, viewSelection, { showType: false } ) )
-					.to.equal( '<div>f<span>o<strong>o</strong>[]<strong>b</strong>a</span>r</div>' );
+					.to.equal( '<div>f<span class="marker">o<strong>o</strong>[]<strong>b</strong>a</span>r</div>' );
 			} );
 
-			it( 'in marker - using view element as element creator function for selection marker conversion', () => {
+			it( 'in marker - using virtual selection descriptor creator', () => {
 				dispatcher.on( 'selectionMarker:marker2', convertSelectionMarker(
-					data => new ViewAttributeElement( 'span', { 'class': data.name } )
+					data => ( { 'class': data.name } )
 				) );
 
 				setModelData( modelDoc, 'foobar' );

+ 8 - 239
packages/ckeditor5-engine/tests/conversion/model-to-view-converters.js

@@ -26,8 +26,6 @@ import {
 	removeAttribute,
 	wrapItem,
 	unwrapItem,
-	wrapRange,
-	unwrapRange,
 	remove,
 	removeUIElement
 } from '../../src/conversion/model-to-view-converters';
@@ -457,235 +455,6 @@ describe( 'model-to-view-converters', () => {
 		} );
 	} );
 
-	describe( 'wrapRange/unwrapRange', () => {
-		let modelText, range, modelElement;
-
-		beforeEach( () => {
-			modelText = new ModelText( 'foobar' );
-			modelElement = new ModelElement( 'paragraph', null, modelText );
-			modelRoot.appendChildren( modelElement );
-
-			const viewText = new ViewText( 'foobar' );
-			const viewElement = new ViewContainerElement( 'p', null, viewText );
-			viewRoot.appendChildren( viewElement );
-
-			mapper.bindElements( modelElement, viewElement );
-
-			range = ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 );
-		} );
-
-		it( 'should convert adding/removing of marker into wrapping element in a view', () => {
-			const viewSpan = new ViewAttributeElement( 'span', { class: 'name' } );
-
-			dispatcher.on( 'addMarker:name', wrapRange( viewSpan ) );
-			dispatcher.on( 'removeMarker:name', unwrapRange( viewSpan ) );
-
-			dispatcher.convertMarker( 'addMarker', 'name', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="name">ob</span>ar</p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'name', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
-
-		it( 'should convert insert/remove of attribute in model with wrapping element generating function as a parameter', () => {
-			const converterCallback = data => {
-				const name = data.name.split( ':' )[ 1 ];
-
-				return new ViewAttributeElement( 'span', { class: name } );
-			};
-
-			dispatcher.on( 'addMarker:name', wrapRange( converterCallback ) );
-			dispatcher.on( 'removeMarker:name', unwrapRange( converterCallback ) );
-
-			dispatcher.convertMarker( 'addMarker', 'name:john', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="john">ob</span>ar</p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'name:john', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
-
-		it( 'should support non-flat markers', () => {
-			const modelElement2 = new ModelElement( 'paragraph', null, new ModelText( '22' ) );
-			modelRoot.appendChildren( modelElement2 );
-
-			const modelElement3 = new ModelElement( 'paragraph', null, new ModelText( '333' ) );
-			modelRoot.appendChildren( modelElement3 );
-
-			const viewElement2 = new ViewContainerElement( 'p', null, new ViewText( '22' ) );
-			viewRoot.appendChildren( viewElement2 );
-
-			const viewElement3 = new ViewContainerElement( 'p', null, new ViewText( '333' ) );
-			viewRoot.appendChildren( viewElement3 );
-
-			mapper.bindElements( modelElement2, viewElement2 );
-			mapper.bindElements( modelElement3, viewElement3 );
-
-			const range = ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement3, 1 );
-			const viewSpan = new ViewAttributeElement( 'span', { class: 'name' } );
-
-			dispatcher.on( 'addMarker:name', wrapRange( viewSpan ) );
-			dispatcher.on( 'removeMarker:name', unwrapRange( viewSpan ) );
-
-			dispatcher.convertMarker( 'addMarker', 'name', range );
-
-			expect( viewToString( viewRoot ) ).to.equal(
-				'<div><p>fo<span class="name">obar</span></p><p><span class="name">22</span></p><p><span class="name">3</span>33</p></div>'
-			);
-
-			dispatcher.convertMarker( 'removeMarker', 'name', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p><p>22</p><p>333</p></div>' );
-		} );
-
-		it( 'should be possible to override wrapRange', () => {
-			const converterCallback = data => {
-				const name = data.name.split( ':' )[ 1 ];
-
-				return new ViewAttributeElement( 'span', { class: name } );
-			};
-
-			dispatcher.on( 'addMarker:name', wrapRange( converterCallback ) );
-			dispatcher.on( 'addMarker:name:john', ( evt, data, consumable ) => {
-				consumable.consume( data.range, 'addMarker' );
-			}, { priority: 'high' } );
-
-			dispatcher.convertMarker( 'addMarker', 'name:john', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
-
-		it( 'should be possible to override unwrapRange', () => {
-			const converterCallback = data => {
-				const name = data.name.split( ':' )[ 1 ];
-
-				return new ViewAttributeElement( 'span', { class: name } );
-			};
-
-			dispatcher.on( 'addMarker:name', wrapRange( converterCallback ) );
-			dispatcher.on( 'removeMarker:name', unwrapRange( converterCallback ) );
-			dispatcher.on( 'removeMarker:name:john', ( evt, data, consumable ) => {
-				consumable.consume( data.range, 'removeMarker' );
-			}, { priority: 'high' } );
-
-			dispatcher.convertMarker( 'addMarker', 'name:john', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="john">ob</span>ar</p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'name:john', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="john">ob</span>ar</p></div>' );
-		} );
-
-		it( 'should not convert or consume if view element is not returned by element generating function', () => {
-			const converterCallback = () => null;
-
-			sinon.spy( dispatcher, 'fire' );
-
-			dispatcher.on( 'addMarker:name', wrapRange( converterCallback ) );
-			dispatcher.on( 'addMarker:name', ( evt, data, consumable ) => {
-				// Check whether value was not consumed from `consumable`.
-				expect( consumable.test( data.range, 'addMarker' ) ).to.be.true;
-			} );
-
-			dispatcher.on( 'removeMarker:name', unwrapRange( converterCallback ) );
-			dispatcher.on( 'removeMarker:name', ( evt, data, consumable ) => {
-				// Check whether value was not consumed from `consumable`.
-				expect( consumable.test( data.range, 'removeMarker' ) ).to.be.true;
-			} );
-
-			dispatcher.convertMarker( 'addMarker', 'name', range );
-
-			expect( dispatcher.fire.calledWith( 'addMarker:name' ) ).to.be.true;
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'name', range );
-
-			expect( dispatcher.fire.calledWith( 'removeMarker:name' ) ).to.be.true;
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
-
-		it( 'multiple overlapping non-collapsed markers', () => {
-			const converterCallbackName = data => {
-				const name = data.name.split( ':' )[ 1 ];
-				const element = new ViewAttributeElement( 'span', { class: name } );
-				element.priority = name.charCodeAt( 0 );
-
-				return element;
-			};
-			const converterCallbackSearch = () => new ViewAttributeElement( 'em', { class: 'search' } );
-
-			dispatcher.on( 'addMarker:name', wrapRange( converterCallbackName ) );
-			dispatcher.on( 'removeMarker:name', unwrapRange( converterCallbackName ) );
-			dispatcher.on( 'addMarker:search', wrapRange( converterCallbackSearch ) );
-			dispatcher.on( 'removeMarker:search', unwrapRange( converterCallbackSearch ) );
-
-			dispatcher.convertMarker( 'addMarker', 'name:a', range );
-			dispatcher.convertMarker( 'addMarker', 'name:b', range );
-			dispatcher.convertMarker( 'addMarker', 'search', range );
-
-			expect( viewToString( viewRoot ) ).to.equal(
-				'<div><p>fo<em class="search"><span class="a"><span class="b">ob</span></span></em>ar</p></div>'
-			);
-
-			dispatcher.convertMarker( 'removeMarker', 'name:b', range );
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<em class="search"><span class="a">ob</span></em>ar</p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'search', range );
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>fo<span class="a">ob</span>ar</p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'name:a', range );
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
-
-		it( 'multiple overlapping non-collapsed markers intersecting with same priority', () => {
-			const converterCallbackSearch = () => new ViewAttributeElement( 'em', { class: 'search' } );
-
-			dispatcher.on( 'addMarker:search', wrapRange( converterCallbackSearch ) );
-			dispatcher.on( 'removeMarker:search', unwrapRange( converterCallbackSearch ) );
-
-			const range1 = ModelRange.createFromParentsAndOffsets( modelElement, 1, modelElement, 3 );
-			const range2 = ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 4 );
-			const range3 = ModelRange.createFromParentsAndOffsets( modelElement, 4, modelElement, 6 );
-
-			dispatcher.convertMarker( 'addMarker', 'search', range1 );
-			dispatcher.convertMarker( 'addMarker', 'search', range2 );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>f<em class="search">oob</em>ar</p></div>' );
-
-			dispatcher.convertMarker( 'addMarker', 'search', range3 );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>f<em class="search">oobar</em></p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'search', range2 );
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>f<em class="search">o</em>ob<em class="search">ar</em></p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'search', range3 );
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>f<em class="search">o</em>obar</p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'search', range1 );
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
-
-		it( 'should do nothing when range is collapsed', () => {
-			const viewSpan = new ViewAttributeElement( 'span', { class: 'name' } );
-
-			dispatcher.on( 'addMarker:name', wrapRange( viewSpan ) );
-			dispatcher.on( 'removeMarker:name', unwrapRange( viewSpan ) );
-
-			dispatcher.convertMarker( 'addMarker', 'name', ModelRange.createFromParentsAndOffsets( modelElement, 2, modelElement, 2 ) );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-
-			dispatcher.convertMarker( 'removeMarker', 'name', range );
-
-			expect( viewToString( viewRoot ) ).to.equal( '<div><p>foobar</p></div>' );
-		} );
-	} );
-
 	describe( 'insertUIElement/removeUIElement', () => {
 		let modelText, range, modelElement;
 
@@ -742,11 +511,11 @@ describe( 'model-to-view-converters', () => {
 			dispatcher.on( 'removeMarker:marker', removeUIElement( viewUi ) );
 
 			dispatcher.on( 'addMarker:marker', ( evt, data, consumable ) => {
-				expect( consumable.test( data.range, 'addMarker' ) ).to.be.true;
+				expect( consumable.test( data.range, 'addMarker:marker' ) ).to.be.true;
 			} );
 
 			dispatcher.on( 'removeMarker:marker', ( evt, data, consumable ) => {
-				expect( consumable.test( data.range, 'removeMarker' ) ).to.be.true;
+				expect( consumable.test( data.range, 'removeMarker:marker' ) ).to.be.true;
 			} );
 
 			dispatcher.convertMarker( 'addMarker', 'marker', range );
@@ -769,11 +538,11 @@ describe( 'model-to-view-converters', () => {
 			dispatcher.on( 'removeMarker:marker', removeUIElement( viewUi ) );
 
 			dispatcher.on( 'addMarker:marker', ( evt, data, consumable ) => {
-				consumable.consume( data.range, 'addMarker' );
+				consumable.consume( data.range, 'addMarker:marker' );
 			}, { priority: 'high' } );
 
 			dispatcher.on( 'removeMarker:marker', ( evt, data, consumable ) => {
-				consumable.consume( data.range, 'removeMarker' );
+				consumable.consume( data.range, 'removeMarker:marker' );
 			}, { priority: 'high' } );
 
 			dispatcher.convertMarker( 'addMarker', 'marker', range );
@@ -796,11 +565,11 @@ describe( 'model-to-view-converters', () => {
 			dispatcher.on( 'removeMarker:marker', removeUIElement( viewUi ) );
 
 			dispatcher.on( 'addMarker:marker', ( evt, data, consumable ) => {
-				expect( consumable.test( data.range, 'addMarker' ) ).to.be.true;
+				expect( consumable.test( data.range, 'addMarker:marker' ) ).to.be.true;
 			} );
 
 			dispatcher.on( 'removeMarker:marker', ( evt, data, consumable ) => {
-				expect( consumable.test( data.range, 'removeMarker' ) ).to.be.true;
+				expect( consumable.test( data.range, 'removeMarker:marker' ) ).to.be.true;
 			} );
 
 			dispatcher.convertMarker( 'addMarker', 'marker', range );
@@ -823,11 +592,11 @@ describe( 'model-to-view-converters', () => {
 			dispatcher.on( 'removeMarker:marker', removeUIElement( viewUi ) );
 
 			dispatcher.on( 'addMarker:marker', ( evt, data, consumable ) => {
-				consumable.consume( data.range, 'addMarker' );
+				consumable.consume( data.range, 'addMarker:marker' );
 			}, { priority: 'high' } );
 
 			dispatcher.on( 'removeMarker:marker', ( evt, data, consumable ) => {
-				consumable.consume( data.range, 'removeMarker' );
+				consumable.consume( data.range, 'removeMarker:marker' );
 			}, { priority: 'high' } );
 
 			dispatcher.convertMarker( 'addMarker', 'marker', range );

+ 14 - 3
packages/ckeditor5-engine/tests/conversion/modelconversiondispatcher.js

@@ -550,7 +550,10 @@ describe( 'ModelConversionDispatcher', () => {
 		let range;
 
 		beforeEach( () => {
-			range = ModelRange.createFromParentsAndOffsets( root, 0, root, 4 );
+			const element = new ModelElement( 'paragraph', null, [ new ModelText( 'foo bar baz' ) ] );
+			root.appendChildren( [ element ] );
+
+			range = ModelRange.createFromParentsAndOffsets( element, 0, element, 4 );
 		} );
 
 		it( 'should fire event based on passed parameters', () => {
@@ -594,11 +597,19 @@ describe( 'ModelConversionDispatcher', () => {
 
 		it( 'should prepare consumable values', () => {
 			dispatcher.on( 'addMarker:name', ( evt, data, consumable ) => {
-				expect( consumable.test( data.range, 'addMarker' ) ).to.be.true;
+				if ( data.item ) {
+					expect( consumable.test( data.item, 'addMarker:name' ) ).to.be.true;
+				} else {
+					expect( consumable.test( data.range, 'addMarker:name' ) ).to.be.true;
+				}
 			} );
 
 			dispatcher.on( 'removeMarker:name', ( evt, data, consumable ) => {
-				expect( consumable.test( data.range, 'removeMarker' ) ).to.be.true;
+				if ( data.item ) {
+					expect( consumable.test( data.item, 'removeMarker:name' ) ).to.be.true;
+				} else {
+					expect( consumable.test( data.range, 'removeMarker:name' ) ).to.be.true;
+				}
 			} );
 
 			dispatcher.convertMarker( 'addMarker', 'name', range );