Explorar el Código

Changed: make move and remove conversion dispatching similar to other change types dispatching.

Szymon Cofalik hace 9 años
padre
commit
350cc25ca5

+ 14 - 22
packages/ckeditor5-engine/src/conversion/model-to-view-converters.js

@@ -3,7 +3,6 @@
  * For licensing, see LICENSE.md.
  */
 
-import ModelTreeWalker from '../model/treewalker.js';
 import ModelRange from '../model/range.js';
 
 import ViewElement from '../view/element.js';
@@ -283,21 +282,15 @@ export function unwrap( elementCreator ) {
  * @returns {Function} Move event converter.
  */
 export function move() {
-	return ( evt, data, conversionApi ) => {
-		const walker = new ModelTreeWalker( { boundaries: data.range, shallow: true } );
+	return ( evt, data, consumable, conversionApi ) => {
+		if ( consumable.consume( data.item, 'move' ) ) {
+			const sourceModelRange = ModelRange.createFromPositionAndShift( data.sourcePosition, data.item.offsetSize );
+			const sourceViewRange = conversionApi.mapper.toViewRange( sourceModelRange );
 
-		let length = 0;
+			const targetViewPosition = conversionApi.mapper.toViewPosition( data.targetPosition );
 
-		for ( let value of walker ) {
-			length += value.length;
+			viewWriter.move( sourceViewRange, targetViewPosition );
 		}
-
-		const sourceModelRange = ModelRange.createFromPositionAndShift( data.sourcePosition, length );
-
-		const sourceViewRange = conversionApi.mapper.toViewRange( sourceModelRange );
-		const targetViewPosition = conversionApi.mapper.toViewPosition( data.range.start );
-
-		viewWriter.move( sourceViewRange, targetViewPosition );
 	};
 }
 
@@ -311,19 +304,18 @@ export function move() {
  * @returns {Function} Remove event converter.
  */
 export function remove() {
-	return ( evt, data, conversionApi ) => {
-		const walker = new ModelTreeWalker( { boundaries: data.range, shallow: true } );
+	return ( evt, data, consumable, conversionApi ) => {
+		if ( consumable.consume( data.item, 'remove' ) ) {
+			const sourceModelRange = ModelRange.createFromPositionAndShift( data.sourcePosition, data.item.offsetSize );
+			const sourceViewRange = conversionApi.mapper.toViewRange( sourceModelRange );
 
-		let length = 0;
+			viewWriter.remove( sourceViewRange );
 
-		for ( let value of walker ) {
-			length += value.length;
+			conversionApi.mapper.unbindModelElement( data.item );
 		}
+	};
+}
 
-		const sourceModelRange = ModelRange.createFromPositionAndShift( data.sourcePosition, length );
-		const sourceViewRange = conversionApi.mapper.toViewRange( sourceModelRange );
-
-		viewWriter.remove( sourceViewRange );
 	};
 }
 

+ 34 - 22
packages/ckeditor5-engine/src/conversion/modelconversiondispatcher.js

@@ -5,6 +5,7 @@
 
 import Consumable from './modelconsumable.js';
 import Range from '../model/range.js';
+import Position from '../model/position.js';
 import TextProxy from '../model/textproxy.js';
 import EmitterMixin from '../../utils/emittermixin.js';
 import mix from '../../utils/mix.js';
@@ -195,12 +196,20 @@ export default class ModelConversionDispatcher {
 	 * @param {engine.model.Range} range Moved range (after move).
 	 */
 	convertMove( sourcePosition, range ) {
-		const data = {
-			sourcePosition: sourcePosition,
-			range: range
-		};
+		const consumable = this._createConsumableForRange( range, 'move' );
+
+		// Fire a separate event for each top-most node and text fragment contained in the range.
+		const items = Array.from( range.getItems( { shallow: true } ) ).reverse();
+
+		for ( let item of items ) {
+			const data = {
+				sourcePosition: sourcePosition.getShiftedBy( item.startOffset - range.start.offset ),
+				targetPosition: Position.createAt( range.start ),
+				item: item
+			};
 
-		this.fire( 'move', data, this.conversionApi );
+			this._testAndFire( 'move', data, consumable );
+		}
 	}
 
 	/**
@@ -211,12 +220,19 @@ export default class ModelConversionDispatcher {
 	 * @param {engine.model.Range} range Removed range (after remove, in {@link engine.model.Document#graveyard graveyard root}).
 	 */
 	convertRemove( sourcePosition, range ) {
-		const data = {
-			sourcePosition: sourcePosition,
-			range: range
-		};
+		const consumable = this._createConsumableForRange( range, 'remove' );
+
+		// Fire a separate event for each top-most node and text fragment contained in the range.
+		const items = Array.from( range.getItems( { shallow: true } ) ).reverse();
 
-		this.fire( 'remove', data, this.conversionApi );
+		for ( let item of items ) {
+			const data = {
+				sourcePosition: sourcePosition.getShiftedBy( item.startOffset - range.start.offset ),
+				item: item
+			};
+
+			this._testAndFire( 'remove', data, consumable );
+		}
 	}
 
 	/**
@@ -233,7 +249,7 @@ export default class ModelConversionDispatcher {
 	 */
 	convertAttribute( type, range, key, oldValue, newValue ) {
 		// Create a list with attributes to consume.
-		const consumable = this._createAttributeConsumable( type, range, key );
+		const consumable = this._createConsumableForRange( range, type + ':' + key );
 
 		// Create a separate attribute event for each node in the range.
 		for ( let value of range ) {
@@ -302,22 +318,18 @@ export default class ModelConversionDispatcher {
 	}
 
 	/**
-	 * Creates {@link engine.conversion.ModelConsumable} with values to consume from given range, assuming that
-	 * given range has just had it's attributes changed.
+	 * Creates {@link engine.conversion.ModelConsumable} with values of given `type` for each item from given `range`.
 	 *
 	 * @private
-	 * @param {String} type Change type. Possible values: `addAttribute`, `removeAttribute`, `changeAttribute`.
-	 * @param {engine.conversion.Range} range Changed range.
-	 * @param {String} key Attribute key.
+	 * @param {engine.conversion.Range} range Affected range.
+	 * @param {String} type Consumable type.
 	 * @returns {engine.conversion.ModelConsumable} Values to consume.
 	 */
-	_createAttributeConsumable( type, range, key ) {
+	_createConsumableForRange( range, type ) {
 		const consumable = new Consumable();
 
-		for ( let value of range ) {
-			const item = value.item;
-
-			consumable.add( item, type + ':' + key );
+		for ( let item of range.getItems() ) {
+			consumable.add( item, type );
 		}
 
 		return consumable;
@@ -360,7 +372,7 @@ export default class ModelConversionDispatcher {
 			return;
 		}
 
-		if ( type === 'insert' ) {
+		if ( type === 'insert' || type === 'remove' || type == 'move' ) {
 			if ( data.item instanceof TextProxy ) {
 				// Example: insert:$text.
 				this.fire( type + ':$text', data, consumable, this.conversionApi );