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

Refactored conversion to use writer instead of batch.

Oskar Wróbel 8 лет назад
Родитель
Сommit
a26bdcaa07

+ 2 - 2
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -104,7 +104,7 @@ export default class DataController {
 		 * @readonly
 		 * @member {module:engine/conversion/viewconversiondispatcher~ViewConversionDispatcher}
 		 */
-		this.viewToModel = new ViewConversionDispatcher( {
+		this.viewToModel = new ViewConversionDispatcher( this.model, {
 			schema: model.schema
 		} );
 
@@ -188,7 +188,7 @@ export default class DataController {
 		// Save to model.
 		const modelRoot = this.model.document.getRoot( rootName );
 
-		this.model.enqueueChanges( 'transparent', writer => {
+		this.model.enqueueChange( 'transparent', writer => {
 			// Clearing selection is a workaround for ticket #569 (LiveRange loses position after removing data from document).
 			// After fixing it this code should be removed.
 			this.model.document.selection.removeAllRanges();

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

@@ -106,7 +106,7 @@ export default class EditingController {
 		} );
 
 		// Convert view selection to model.
-		this.listenTo( this.view, 'selectionChange', convertSelectionChange( this.model.document, this.mapper ) );
+		this.listenTo( this.view, 'selectionChange', convertSelectionChange( this.model, this.mapper ) );
 
 		// Attach default content converters.
 		this.modelToView.on( 'insert:$text', insertText(), { priority: 'lowest' } );

+ 7 - 7
packages/ckeditor5-engine/src/conversion/buildviewconverter.js

@@ -263,14 +263,14 @@ class ViewConverterBuilder {
 	 *		buildViewConverter().for( dispatcher ).fromElement( 'p' ).toElement( 'paragraph' );
 	 *		buildViewConverter().for( dispatcher )
 	 *			.fromElement( 'img' )
-	 *			.toElement( ( viewElement, batch ) => batch.createElement( 'image', { src: viewElement.getAttribute( 'src' ) } ) );
+	 *			.toElement( ( viewElement, writer ) => writer.createElement( 'image', { src: viewElement.getAttribute( 'src' ) } ) );
 	 *
 	 * @param {String|Function} element Model element name or model element creator function.
 	 */
 	toElement( element ) {
 		function eventCallbackGen( from ) {
 			return ( evt, data, consumable, conversionApi ) => {
-				const batch = conversionApi.batch;
+				const writer = conversionApi.writer;
 
 				// There is one callback for all patterns in the matcher.
 				// This will be usually just one pattern but we support matchers with many patterns too.
@@ -284,7 +284,7 @@ class ViewConverterBuilder {
 				// Now, for every match between matcher and actual element, we will try to consume the match.
 				for ( const match of matchAll ) {
 					// Create model element basing on creator function or element name.
-					const modelElement = element instanceof Function ? element( data.input, batch ) : batch.createElement( element );
+					const modelElement = element instanceof Function ? element( data.input, writer ) : writer.createElement( element );
 
 					// Do not convert if element building function returned falsy value.
 					if ( !modelElement ) {
@@ -311,7 +311,7 @@ class ViewConverterBuilder {
 					const modelChildren = conversionApi.convertChildren( data.input, consumable, data );
 
 					for ( const child of Array.from( modelChildren ) ) {
-						batch.append( child, modelElement );
+						writer.append( child, modelElement );
 					}
 
 					// Remove created `modelElement` from the parents stack.
@@ -435,7 +435,7 @@ class ViewConverterBuilder {
 	toMarker( creator ) {
 		function eventCallbackGen( from ) {
 			return ( evt, data, consumable, conversionApi ) => {
-				const batch = conversionApi.batch;
+				const writer = conversionApi.writer;
 
 				// There is one callback for all patterns in the matcher.
 				// This will be usually just one pattern but we support matchers with many patterns too.
@@ -453,7 +453,7 @@ class ViewConverterBuilder {
 					modelElement = creator( data.input );
 				// When there is no creator then create model element basing on data from view element.
 				} else {
-					modelElement = batch.createElement( '$marker', { 'data-name': data.input.getAttribute( 'data-name' ) } );
+					modelElement = writer.createElement( '$marker', { 'data-name': data.input.getAttribute( 'data-name' ) } );
 				}
 
 				// Check if model element is correct (has proper name and property).
@@ -528,7 +528,7 @@ function setAttributeOn( toChange, attribute, data, conversionApi ) {
 	};
 
 	if ( conversionApi.schema.check( schemaQuery ) ) {
-		conversionApi.batch.setAttribute( attribute.key, attribute.value, toChange );
+		conversionApi.writer.setAttribute( attribute.key, attribute.value, toChange );
 	}
 }
 

+ 6 - 6
packages/ckeditor5-engine/src/conversion/modelconversiondispatcher.js

@@ -110,17 +110,17 @@ export default class ModelConversionDispatcher {
 	/**
 	 * Creates a `ModelConversionDispatcher` that operates using passed API.
 	 *
-	 * @param {module:engine/model/document~Document} modelDocument Model document instance bound with this dispatcher.
+	 * @param {module:engine/model/document~Document} model Data model.
 	 * @param {Object} [conversionApi] Interface passed by dispatcher to the events callbacks.
 	 */
-	constructor( modelDocument, conversionApi = {} ) {
+	constructor( model, conversionApi = {} ) {
 		/**
-		 * Model document instance bound with this dispatcher.
+		 * Data model instance bound with this dispatcher.
 		 *
 		 * @private
 		 * @member {module:engine/model/document~Document}
 		 */
-		this._modelDocument = modelDocument;
+		this._model = model;
 
 		/**
 		 * Interface passed by dispatcher to the events callbacks.
@@ -215,7 +215,7 @@ export default class ModelConversionDispatcher {
 			}
 		}
 
-		for ( const marker of this._modelDocument.markers ) {
+		for ( const marker of this._model.markers ) {
 			const markerRange = marker.getRange();
 			const intersection = markerRange.getIntersection( range );
 
@@ -357,7 +357,7 @@ export default class ModelConversionDispatcher {
 	 * @param {module:engine/model/selection~Selection} selection Selection to convert.
 	 */
 	convertSelection( selection ) {
-		const markers = Array.from( this._modelDocument.markers.getMarkersAtPosition( selection.getFirstPosition() ) );
+		const markers = Array.from( this._model.markers.getMarkersAtPosition( selection.getFirstPosition() ) );
 		const consumable = this._createSelectionConsumable( selection, markers );
 
 		this.fire( 'selection', { selection }, consumable, this.conversionApi );

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

@@ -22,11 +22,11 @@ import ModelSelection from '../model/selection';
  *
  *		view.document.on( 'selectionChange', convertSelectionChange( modelDocument, mapper ) );
  *
- * @param {module:engine/model/document~Document} modelDocument Model document on which selection should be updated.
+ * @param {module:engine/model/model~Model} model Data model.
  * @param {module:engine/conversion/mapper~Mapper} mapper Conversion mapper.
  * @returns {Function} {@link module:engine/view/document~Document#event:selectionChange} callback function.
  */
-export function convertSelectionChange( modelDocument, mapper ) {
+export function convertSelectionChange( model, mapper ) {
 	return ( evt, data ) => {
 		const viewSelection = data.newSelection;
 		const modelSelection = new ModelSelection();
@@ -39,9 +39,9 @@ export function convertSelectionChange( modelDocument, mapper ) {
 
 		modelSelection.setRanges( ranges, viewSelection.isBackward );
 
-		if ( !modelSelection.isEqual( modelDocument.selection ) ) {
-			modelDocument.enqueueChanges( () => {
-				modelDocument.selection.setTo( modelSelection );
+		if ( !modelSelection.isEqual( model.document.selection ) ) {
+			model.enqueueChanges( () => {
+				model.document.selection.setTo( modelSelection );
 			} );
 		}
 	};

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

@@ -48,7 +48,7 @@ export function convertText() {
 
 		if ( conversionApi.schema.check( schemaQuery ) ) {
 			if ( consumable.consume( data.input ) ) {
-				data.output = conversionApi.batch.createText( data.input.data );
+				data.output = conversionApi.writer.createText( data.input.data );
 			}
 		}
 	};

+ 41 - 31
packages/ckeditor5-engine/src/conversion/viewconversiondispatcher.js

@@ -91,7 +91,7 @@ import log from '@ckeditor/ckeditor5-utils/src/log';
  *		// Fire conversion.
  *		// Always take care where the converted model structure will be appended to. If this `viewDocumentFragment`
  *		// is going to be appended directly to a '$root' element, use that in `context`.
- *		viewDispatcher.convert( viewDocumentFragment, batch, { context: [ '$root' ] } );
+ *		viewDispatcher.convert( viewDocumentFragment, { context: [ '$root' ] } );
  *
  * Before each conversion process, `ViewConversionDispatcher` fires {@link ~ViewConversionDispatcher#event:viewCleanup}
  * event which can be used to prepare tree view for conversion.
@@ -107,10 +107,19 @@ export default class ViewConversionDispatcher {
 	 * Creates a `ViewConversionDispatcher` that operates using passed API.
 	 *
 	 * @see module:engine/conversion/viewconversiondispatcher~ViewConversionApi
+	 * @param {module:engine/model/model~Model} model Data model.
 	 * @param {Object} [conversionApi] Additional properties for interface that will be passed to events fired
 	 * by `ViewConversionDispatcher`.
 	 */
-	constructor( conversionApi = {} ) {
+	constructor( model, conversionApi = {} ) {
+		/**
+		 * Data model.
+		 *
+		 * @private
+		 * @type {module:engine/model/model~Model}
+		 */
+		this._model = model;
+
 		/**
 		 * Interface passed by dispatcher to the events callbacks.
 		 *
@@ -122,9 +131,6 @@ export default class ViewConversionDispatcher {
 		// set on `conversionApi`. This way only a part of `ViewConversionDispatcher` API is exposed.
 		this.conversionApi.convertItem = this._convertItem.bind( this );
 		this.conversionApi.convertChildren = this._convertChildren.bind( this );
-
-		// Batch used for conversion. Is passed to #convert method and removed at the and of the conversion.
-		this.conversionApi.batch = null;
 	}
 
 	/**
@@ -135,40 +141,44 @@ export default class ViewConversionDispatcher {
 	 * @fires documentFragment
 	 * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element} viewItem
 	 * Part of the view to be converted.
-	 * @param {module:engine/model/batch~Batch} batch Batch to which the deltas will be added.
 	 * @param {Object} additionalData Additional data to be passed in `data` argument when firing `ViewConversionDispatcher`
 	 * events. See also {@link ~ViewConversionDispatcher#event:element element event}.
 	 * @returns {module:engine/model/documentfragment~DocumentFragment} Model data that is a result of the conversion process
 	 * wrapped in `DocumentFragment`. Converted marker elements will be set as that document fragment's
 	 * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.
 	 */
-	convert( viewItem, batch, additionalData ) {
-		// Store batch in current conversion as conversionApi, will be removed at the end of this conversion.
-		this.conversionApi.batch = batch;
+	convert( viewItem, additionalData ) {
+		return this._model.change( writer => {
+			// Store writer in current conversion as a conversion API.
+			this.conversionApi.writer = writer;
 
-		this.fire( 'viewCleanup', viewItem );
+			this.fire( 'viewCleanup', viewItem );
 
-		const consumable = ViewConsumable.createFrom( viewItem );
-		let conversionResult = this._convertItem( viewItem, consumable, additionalData );
+			const consumable = ViewConsumable.createFrom( viewItem );
+			let conversionResult = this._convertItem( viewItem, consumable, additionalData );
 
-		// We can get a null here if conversion failed (see _convertItem())
-		// or simply if an item could not be converted (e.g. due to the schema).
-		if ( !conversionResult ) {
-			return batch.createDocumentFragment();
-		}
+			// Remove writer from conversion API after conversion.
+			this.conversionApi.writer = null;
 
-		// When conversion result is not a document fragment we need to wrap it in document fragment.
-		if ( !conversionResult.is( 'documentFragment' ) ) {
-			const docFrag = batch.createDocumentFragment();
+			// We can get a null here if conversion failed (see _convertItem())
+			// or simply if an item could not be converted (e.g. due to the schema).
+			if ( !conversionResult ) {
+				return writer.createDocumentFragment();
+			}
 
-			batch.append( conversionResult, docFrag );
-			conversionResult = docFrag;
-		}
+			// When conversion result is not a document fragment we need to wrap it in document fragment.
+			if ( !conversionResult.is( 'documentFragment' ) ) {
+				const docFrag = writer.createDocumentFragment();
 
-		// Extract temporary markers elements from model and set as static markers collection.
-		conversionResult.markers = extractMarkersFromModelFragment( conversionResult, batch );
+				writer.append( conversionResult, docFrag );
+				conversionResult = docFrag;
+			}
 
-		return conversionResult;
+			// Extract temporary markers elements from model and set as static markers collection.
+			conversionResult.markers = extractMarkersFromModelFragment( conversionResult, writer );
+
+			return conversionResult;
+		} );
 	}
 
 	/**
@@ -212,14 +222,14 @@ export default class ViewConversionDispatcher {
 	 * @see module:engine/conversion/viewconversiondispatcher~ViewConversionApi#convertChildren
 	 */
 	_convertChildren( input, consumable, additionalData ) {
-		const batch = this.conversionApi.batch;
-		const documentFragment = batch.createDocumentFragment();
+		const writer = this.conversionApi.writer;
+		const documentFragment = writer.createDocumentFragment();
 
 		for ( const viewChild of Array.from( input.getChildren() ) ) {
 			const modelChild = this._convertItem( viewChild, consumable, additionalData );
 
 			if ( modelChild instanceof ModelNode || modelChild instanceof ModelDocumentFragment ) {
-				batch.append( modelChild, documentFragment );
+				writer.append( modelChild, documentFragment );
 			}
 		}
 
@@ -281,7 +291,7 @@ mix( ViewConversionDispatcher, EmitterMixin );
 //
 // @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/node~Node} modelItem Fragment of model.
 // @returns {Map<String, module:engine/model/range~Range>} List of static markers.
-function extractMarkersFromModelFragment( modelItem, batch ) {
+function extractMarkersFromModelFragment( modelItem, writer ) {
 	const markerElements = new Set();
 	const markers = new Map();
 
@@ -313,7 +323,7 @@ function extractMarkersFromModelFragment( modelItem, batch ) {
 		}
 
 		// Remove marker element from DocumentFragment.
-		batch.remove( markerElement );
+		writer.remove( markerElement );
 	}
 
 	return markers;

+ 16 - 11
packages/ckeditor5-engine/src/model/documentselection.js

@@ -557,7 +557,9 @@ export default class DocumentSelection extends Selection {
 	_removeStoredAttribute( key ) {
 		const storeKey = DocumentSelection._getStoreAttributeKey( key );
 
-		this._document.batch().removeAttribute( storeKey, this.anchor.parent );
+		this._model.change( writer => {
+			writer.removeAttribute( storeKey, this.anchor.parent );
+		} );
 	}
 
 	/**
@@ -570,7 +572,9 @@ export default class DocumentSelection extends Selection {
 	_storeAttribute( key, value ) {
 		const storeKey = DocumentSelection._getStoreAttributeKey( key );
 
-		this._document.batch().setAttribute( storeKey, value, this.anchor.parent );
+		this._model.change( writer => {
+			writer.setAttribute( storeKey, value, this.anchor.parent );
+		} );
 	}
 
 	/**
@@ -581,19 +585,20 @@ export default class DocumentSelection extends Selection {
 	 */
 	_setStoredAttributesTo( attrs ) {
 		const selectionParent = this.anchor.parent;
-		const batch = this._document.batch();
 
-		for ( const [ oldKey ] of this._getStoredAttributes() ) {
-			const storeKey = DocumentSelection._getStoreAttributeKey( oldKey );
+		this._model.change( writer => {
+			for ( const [ oldKey ] of this._getStoredAttributes() ) {
+				const storeKey = DocumentSelection._getStoreAttributeKey( oldKey );
 
-			batch.removeAttribute( storeKey, selectionParent );
-		}
+				writer.removeAttribute( storeKey, selectionParent );
+			}
 
-		for ( const [ key, value ] of attrs ) {
-			const storeKey = DocumentSelection._getStoreAttributeKey( key );
+			for ( const [ key, value ] of attrs ) {
+				const storeKey = DocumentSelection._getStoreAttributeKey( key );
 
-			batch.setAttribute( storeKey, value, selectionParent );
-		}
+				writer.setAttribute( storeKey, value, selectionParent );
+			}
+		} );
 	}
 
 	/**