Sfoglia il codice sorgente

Refactoring virtual selection conversion.

Szymon Kupś 8 anni fa
parent
commit
c34368644f

+ 5 - 86
packages/ckeditor5-engine/src/conversion/buildmodelconverter.js

@@ -15,12 +15,11 @@ import {
 	removeUIElement,
 	wrapItem,
 	unwrapItem,
-	eventNameToConsumableType
+	virtualSelectionConverter
 } from './model-to-view-converters';
 
 import { convertSelectionAttribute, convertSelectionMarker } from './model-selection-to-view-converters';
 
-import ModelRange from '../model/range';
 import ViewAttributeElement from '../view/attributeelement';
 import ViewContainerElement from '../view/containerelement';
 import ViewUIElement from '../view/uielement';
@@ -247,93 +246,13 @@ class ModelConverterBuilder {
 		}
 	}
 
-	toVirtualSelection( selectionInfo ) {
+	toVirtualSelection( selectionDescriptor ) {
 		const priority = this._from.priority === null ? 'normal' : this._from.priority;
 
 		for ( const dispatcher of this._dispatchers ) {
-			dispatcher.on( 'selectionMarker:' + this._from.name, ( evt, data, consumable, api ) => {
-				const info = selectionInfo( data );
-				const wrapElement = new ViewAttributeElement( 'span', info.attributes );
-
-				if ( info.class ) {
-					wrapElement.addClass( info.class );
-				}
-
-				const wrap = convertSelectionMarker( wrapElement );
-
-				wrap( evt, data, consumable, api );
-			}, { priority } );
-
-			dispatcher.on( 'addMarker:' + this._from.name, ( evt, data, consumable, api ) => {
-				const modelItem = data.item;
-				const info = selectionInfo( data );
-
-				if ( modelItem.is( 'textProxy' ) ) {
-					const wrapElement = new ViewAttributeElement( 'span', info.attributes );
-
-					if ( info.class ) {
-						wrapElement.addClass( info.class );
-					}
-
-					const wrap = wrapItem( wrapElement );
-
-					wrap( evt, data, consumable, api );
-				}
-
-				if ( modelItem.is( 'element' ) ) {
-					const consumableType = eventNameToConsumableType( evt.name );
-					const viewElement = api.mapper.toViewElement( modelItem );
-
-					if ( !consumable.consume( modelItem, consumableType ) ) {
-						return;
-					}
-
-					if ( viewElement && viewElement.setVirtualSelection ) {
-						// Virtual selection will be handled by parent element - consume all children.
-						for ( const value of ModelRange.createIn( modelItem ) ) {
-							consumable.consume( value.item, consumableType );
-						}
-
-						viewElement.setVirtualSelection( info );
-					}
-				}
-			}, { priority } );
-
-			dispatcher.on( 'removeMarker:' + this._from.name, ( evt, data, consumable, api ) => {
-				const modelItem = data.item;
-				const info = selectionInfo( data );
-
-				if ( modelItem.is( 'textProxy' ) ) {
-					const info = selectionInfo( data );
-					const wrapElement = new ViewAttributeElement( 'span', info.attributes );
-
-					if ( info.class ) {
-						wrapElement.addClass( info.class );
-					}
-
-					const unwrap = unwrapItem( wrapElement );
-
-					unwrap( evt, data, consumable, api );
-				}
-
-				if ( modelItem.is( 'element' ) ) {
-					const consumableType = eventNameToConsumableType( evt.name );
-					const viewElement = api.mapper.toViewElement( modelItem );
-
-					if ( !consumable.consume( modelItem, consumableType ) ) {
-						return;
-					}
-
-					if ( viewElement && viewElement.setVirtualSelection ) {
-						// Virtual selection will be handled by parent element - consume all children.
-						for ( const value of ModelRange.createIn( modelItem ) ) {
-							consumable.consume( value.item, consumableType );
-						}
-
-						viewElement.removeVirtualSelection( info );
-					}
-				}
-			}, { priority } );
+			dispatcher.on( 'addMarker:' + this._from.name, virtualSelectionConverter( selectionDescriptor ), { priority } );
+			dispatcher.on( 'removeMarker:' + this._from.name, virtualSelectionConverter( selectionDescriptor, false ), { priority } );
+			dispatcher.on( 'selectionMarker:' + this._from.name, convertSelectionMarker( selectionDescriptor ), { priority } );
 		}
 	}
 

+ 6 - 8
packages/ckeditor5-engine/src/conversion/model-selection-to-view-converters.js

@@ -6,6 +6,7 @@
 import ViewElement from '../view/element';
 import ViewRange from '../view/range';
 import viewWriter from '../view/writer';
+import { virtualSelectionDescriptorToAttribute } from './model-to-view-converters';
 
 /**
  * Contains {@link module:engine/model/selection~Selection model selection} to
@@ -173,16 +174,13 @@ export function convertSelectionAttribute( elementCreator ) {
  * or function returning a view element, which will be used for wrapping.
  * @returns {Function} Selection converter.
  */
-export function convertSelectionMarker( elementCreator ) {
+export function convertSelectionMarker( selectionDescriptor ) {
 	return ( evt, data, consumable, conversionApi ) => {
-		const viewElement = elementCreator instanceof ViewElement ?
-			elementCreator.clone( true ) :
-			elementCreator( data, consumable, conversionApi );
-
-		if ( !viewElement ) {
-			return;
-		}
+		const descriptor = typeof selectionDescriptor == 'function' ?
+			selectionDescriptor( data, consumable, conversionApi ) :
+			selectionDescriptor;
 
+		const viewElement = virtualSelectionDescriptorToAttribute( descriptor );
 		const consumableName = 'selectionMarker:' + data.name;
 
 		wrapCollapsedSelectionPosition( data.selection, conversionApi.viewSelection, viewElement, consumable, consumableName );

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

@@ -4,10 +4,12 @@
  */
 
 import ViewElement from '../view/element';
+import ViewAttributeElement from '../view/attributeelement';
 import ViewText from '../view/text';
 import ViewRange from '../view/range';
 import ViewTreeWalker from '../view/treewalker';
 import viewWriter from '../view/writer';
+import ModelRange from '../model/range';
 
 /**
  * Contains {@link module:engine/model/model model} to {@link module:engine/view/view view} converters for
@@ -478,6 +480,42 @@ export function remove() {
 	};
 }
 
+export function virtualSelectionConverter( selectionDescriptor, addMarker = true ) {
+	return ( evt, data, consumable, conversionApi ) =>	{
+		const modelItem = data.item;
+		const descriptor = typeof selectionDescriptor == 'function' ?
+			selectionDescriptor( data, consumable, conversionApi ) :
+			selectionDescriptor;
+
+		if ( modelItem.is( 'textProxy' ) ) {
+			const viewElement = virtualSelectionDescriptorToAttribute( descriptor );
+			const converter = addMarker ? wrapItem( viewElement ) : unwrapItem( viewElement );
+
+			converter( evt, data, consumable, conversionApi );
+		}
+
+		if ( modelItem.is( 'element' ) ) {
+			const consumableType = eventNameToConsumableType( evt.name );
+			const viewElement = conversionApi.mapper.toViewElement( modelItem );
+
+			if ( !consumable.consume( modelItem, consumableType ) ) {
+				return;
+			}
+
+			const selectionHandlingMethod = addMarker ? 'setVirtualSelection' : 'removeVirtualSelection';
+
+			if ( viewElement && viewElement[ selectionHandlingMethod ] ) {
+				// Virtual selection will be handled by parent element - consume all children.
+				for ( const value of ModelRange.createIn( modelItem ) ) {
+					consumable.consume( value.item, consumableType );
+				}
+
+				viewElement[ selectionHandlingMethod ]( descriptor );
+			}
+		}
+	};
+}
+
 // Helper function that shifts given view `position` in a way that returned position is after `howMany` characters compared
 // to the original `position`.
 // Because in view there might be view ui elements splitting text nodes, we cannot simply use `ViewPosition#getShiftedBy()`.
@@ -552,3 +590,13 @@ export function eventNameToConsumableType( evtName ) {
 
 	return parts[ 0 ] + ':' + parts[ 1 ];
 }
+
+export function virtualSelectionDescriptorToAttribute( descriptor ) {
+	const attribute = new ViewAttributeElement( 'span', descriptor.attributes );
+
+	if ( descriptor.class ) {
+		attribute.addClass( descriptor.class );
+	}
+
+	return attribute;
+}

+ 0 - 17
packages/ckeditor5-engine/src/conversion/modelconversiondispatcher.js

@@ -400,7 +400,6 @@ export default class ModelConversionDispatcher {
 		}
 
 		// Create consumable for each item in range.
-		// TODO: better consumable name handling.
 		const consumable = this._createConsumableForRange( range, type + ':' + name.split( ':' )[ 0 ] );
 
 		// Create separate event for each node in the range.
@@ -484,22 +483,6 @@ 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.
 	 *