8
0
Pārlūkot izejas kodu

Move view refreshing logic from downcast helpers to the dispatcher.

Maciej Gołaszewski 5 gadi atpakaļ
vecāks
revīzija
ab6468a467

+ 41 - 4
packages/ckeditor5-engine/src/conversion/downcastdispatcher.js

@@ -349,8 +349,7 @@ export default class DowncastDispatcher {
 			const itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );
 			const data = {
 				item,
-				range: itemRange,
-				isRefresh: true
+				range: itemRange
 			};
 
 			const expectedEventName = getEventName( 'insert', data );
@@ -358,6 +357,15 @@ export default class DowncastDispatcher {
 			// Main element refresh - kinda ugly as we have all items in the range.
 			// TODO: Maybe, an inner range would be better (check children, etc).
 			if ( expectedEventName === 'insert:' + name ) {
+				// Cache current view element of a converted element, might be undefined if first insert.
+				const currentView = this.conversionApi.mapper.toViewElement( data.item );
+
+				if ( currentView ) {
+					// Remove the old view (but hold the reference as it will be used to bring back view items not needed to re-render.
+					// Thanks to the mapper that holds references nothing should blow up.
+					this.conversionApi.writer.remove( currentView );
+				}
+
 				this._testAndFire( 'insert', data );
 
 				// Fire a separate addAttribute event for each attribute that was set on inserted items.
@@ -370,6 +378,35 @@ export default class DowncastDispatcher {
 
 					this._testAndFire( `attribute:${ key }`, data );
 				}
+
+				// Handle reviving removed view items on refreshing main view.
+				if ( currentView ) {
+					const viewElement = this.conversionApi.mapper.toViewElement( data.item );
+
+					// Iterate over new view elements to find "interesting" points - those elements that are mapped to the model.
+					for ( const { item } of this.conversionApi.writer.createRangeIn( viewElement ) ) {
+						const modelItem = this.conversionApi.mapper.toModelElement( item );
+
+						// At this stage we get the update view element, so any mapped model item might be a potential "slot".
+						if ( modelItem ) {
+							const currentViewItem = this.conversionApi.mapper._temporalModelToView.get( modelItem );
+
+							// This of course needs better API, but for now it works.
+							// Mapper.bindSlot() creates mappings as mapper.bindElements() but also binds view element
+							// from view to the model item.
+							if ( currentViewItem ) {
+								// This allows to have a map: updatedView - model - oldView and to retain previously rendered children
+								// from the "slot" element. Those children can be moved to a newly created slot.
+								this.conversionApi.writer.move(
+									this.conversionApi.writer.createRangeIn( currentViewItem ),
+									this.conversionApi.writer.createPositionAt( item, 0 )
+								);
+							}
+						}
+					}
+					// // At this stage old view can be safely removed.
+					//
+				}
 			}
 
 			// If the map has given event it _must_ be converted by main "insert" converter.
@@ -383,7 +420,7 @@ export default class DowncastDispatcher {
 					if ( !mappedPosition.parent.is( '$text' ) ) {
 						this._testAndFire( 'insert', data );
 
-						// TODO: attributes...
+						// TODO: attributes ? Try to re-use convertInsert() here.
 					}
 				} else {
 					const viewElement = this.conversionApi.mapper.toViewElement( item );
@@ -391,7 +428,7 @@ export default class DowncastDispatcher {
 					if ( !viewElement ) {
 						this._testAndFire( 'insert', data );
 
-						// TODO: attributes...
+						// TODO: attributes ? Try to re-use convertInsert() here.
 					}
 				}
 			}

+ 0 - 34
packages/ckeditor5-engine/src/conversion/downcasthelpers.js

@@ -803,9 +803,6 @@ export function wrap( elementCreator ) {
  */
 export function insertElement( elementCreator ) {
 	return ( evt, data, conversionApi ) => {
-		// Cache current view element of a converted element, might be undefined if first insert.
-		const currentView = conversionApi.mapper.toViewElement( data.item );
-
 		// Create view structure:
 		const viewElement = elementCreator( data.item, conversionApi );
 
@@ -819,37 +816,6 @@ export function insertElement( elementCreator ) {
 
 		const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
 
-		// A flag was the simplest way of changing default insertElement behavior.
-		if ( data.isRefresh ) {
-			// Because of lack of a better API...
-
-			// Iterate over new view elements to find "interesting" points - those elements that are mapped to the model.
-			for ( const { item } of conversionApi.writer.createRangeIn( viewElement ) ) {
-				const modelItem = conversionApi.mapper.toModelElement( item );
-
-				// At this stage we get the update view element, so any mapped model item might be a potential "slot".
-				if ( modelItem ) {
-					const currentViewItem = conversionApi.mapper._temporalModelToView.get( modelItem );
-
-					// This of course needs better API, but for now it works.
-					// Mapper.bindSlot() creates mappings as mapper.bindElements() but also binds view element from view to the model item.
-					if ( currentViewItem ) {
-						// This allows to have a map: updatedView - model - oldView and to retain previously rendered children
-						// from the "slot" element. Those children can be moved to a newly created slot.
-						conversionApi.writer.move(
-							conversionApi.writer.createRangeIn( currentViewItem ),
-							conversionApi.writer.createPositionAt( item, 0 )
-						);
-					}
-				}
-			}
-
-			// At this stage old view can be safely removed.
-			if ( currentView ) {
-				conversionApi.writer.remove( currentView );
-			}
-		}
-
 		// Rest of standard insertElement converter.
 		conversionApi.mapper.bindElements( data.item, viewElement );
 		conversionApi.writer.insert( viewPosition, viewElement );