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

PoC: Implement triggerBy handling.

Maciej Gołaszewski 5 лет назад
Родитель
Сommit
aa55061ccc

+ 1 - 0
packages/ckeditor5-engine/src/controller/editingcontroller.js

@@ -91,6 +91,7 @@ export default class EditingController {
 		// Also convert model selection.
 		this.listenTo( doc, 'change', () => {
 			this.view.change( writer => {
+				this.downcastDispatcher.pocCheckChangesForRefresh( doc.differ, writer );
 				this.downcastDispatcher.convertChanges( doc.differ, markers, writer );
 				this.downcastDispatcher.convertSelection( selection, markers, writer );
 			} );

+ 38 - 0
packages/ckeditor5-engine/src/conversion/downcastdispatcher.js

@@ -116,6 +116,8 @@ export default class DowncastDispatcher {
 		 * @member {module:engine/conversion/downcastdispatcher~DowncastConversionApi}
 		 */
 		this.conversionApi = extend( { dispatcher: this }, conversionApi );
+
+		this._map = new Map();
 	}
 
 	/**
@@ -168,6 +170,42 @@ export default class DowncastDispatcher {
 		}
 	}
 
+	mapRefreshEvents( modelName, events = [] ) {
+		for ( const eventName of events ) {
+			this._map.set( eventName, modelName );
+		}
+	}
+
+	pocCheckChangesForRefresh( differ ) {
+		const changes = differ.getChanges();
+
+		const found = [ ...changes ]
+			.filter( ( { type } ) => type === 'attribute' || type === 'insert' || type === 'remove' )
+			.map( entry => {
+				const { range, position, type } = entry;
+				const element = range && range.start.nodeAfter || position && position.parent;
+
+				let eventName;
+
+				if ( type === 'attribute' ) {
+					eventName = `attribute:${ entry.attributeKey }:${ element.name }`;
+				} else {
+					eventName = `${ type }:${ element.name }`;
+				}
+
+				if ( this._map.has( eventName ) ) {
+					const expectedElement = this._map.get( eventName );
+
+					return element.is( 'element', expectedElement ) ? element : element.findAncestor( expectedElement );
+				}
+			} )
+			.filter( element => !!element );
+
+		const elementsToRefresh = new Set( found );
+
+		[ ...elementsToRefresh.values() ].forEach( box => differ._pocRefreshItem( box ) );
+	}
+
 	/**
 	 * Starts a conversion of a range insertion.
 	 *

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

@@ -1387,6 +1387,10 @@ function downcastElementToElement( config ) {
 
 	return dispatcher => {
 		dispatcher.on( 'insert:' + config.model, insertElement( config.view ), { priority: config.converterPriority || 'normal' } );
+
+		if ( config.triggerBy ) {
+			dispatcher.mapRefreshEvents( config.model, config.triggerBy );
+		}
 	};
 }
 

+ 18 - 27
tests/manual/article.js

@@ -40,27 +40,6 @@ function mapMeta( editor ) {
 	};
 }
 
-function boxRefresh( model ) {
-	const differ = model.document.differ;
-
-	const changes = differ.getChanges();
-
-	console.log( `boxRefresh() size: ${ changes.length }` );
-
-	const boxElements = [ ...changes ]
-		.filter( ( { type } ) => type === 'attribute' || type === 'insert' || type === 'remove' )
-		.map( ( { range, position } ) => range && range.start.nodeAfter || position && position.parent )
-		.filter( element => element && element.is( 'element', 'box' ) );
-
-	const boxToRefresh = new Set( boxElements );
-
-	console.group( 'refreshItem' );
-	[ ...boxToRefresh.values() ].forEach( box => differ._pocRefreshItem( box ) );
-	console.groupEnd();
-
-	return boxToRefresh.size > 1;
-}
-
 function getChildren( editor, viewElement ) {
 	return [ ...( editor.editing.view.createRangeIn( viewElement ) ) ]
 		.filter( ( { type } ) => type === 'elementStart' )
@@ -108,8 +87,6 @@ function getBoxUpcastConverter( editor ) {
 }
 
 function downcastBox( modelElement, conversionApi ) {
-	console.log( 'downcastBox' );
-
 	const { writer } = conversionApi;
 
 	const viewBox = writer.createContainerElement( 'div', { class: 'box' } );
@@ -122,7 +99,7 @@ function downcastBox( modelElement, conversionApi ) {
 		if ( meta === 'header' ) {
 			const header = writer.createRawElement( 'div', {
 				class: 'box-meta box-meta-header'
-			}, function( domElement ) {
+			}, domElement => {
 				domElement.innerHTML = `<div class="box-meta-header-title"><h2>${ metaValue.title }</h2></div>`;
 			} );
 
@@ -145,6 +122,17 @@ function downcastBox( modelElement, conversionApi ) {
 
 		writer.insert( writer.createPositionAt( contentWrap, field.index ), viewField );
 		conversionApi.mapper.bindSlotElements( field, viewField );
+
+		// Might be simplified to:
+		//
+		// writer.defineSlot( field, viewField, field.index );
+		//
+		// but would require a converter:
+		//
+		// editor.conversion.for( 'downcast' ).elementToElement( {	// .slotToElement()?
+		// 		model: 'viewField',
+		// 		view: { name: 'div', class: 'box-content-field' }
+		// 	} );
 	}
 
 	// At this point we're inserting whole "component". Equivalent to (JSX-like notation):
@@ -212,11 +200,14 @@ function Box( editor ) {
 
 	editor.conversion.for( 'downcast' ).elementToElement( {
 		model: 'box',
-		view: downcastBox
+		view: downcastBox,
+		triggerBy: [
+			'attribute:meta:box',
+			'insert:boxField',
+			'remove:boxField'
+		]
 	} );
 
-	editor.model.document.registerPostFixer( () => boxRefresh( editor.model ) );
-
 	addBoxMetaButton( editor, 'boxTitle', 'Box title', () => ( {
 		header: { title: `Random title no. ${ getRandom() }.` }
 	} ) );