Explorar o código

Tests: Added support for Schema and conversion context in view conversion. Fixed some docs.

Szymon Cofalik %!s(int64=9) %!d(string=hai) anos
pai
achega
b6020a6141

+ 11 - 4
packages/ckeditor5-engine/src/treecontroller/view-to-model-converters.js

@@ -35,7 +35,7 @@ export function convertToModelFragment() {
 	return ( evt, data, consumable, conversionApi ) => {
 		// Second argument in `consumable.test` is discarded for ViewDocumentFragment but is needed for ViewElement.
 		if ( !data.output && consumable.test( data.input, { name: true } ) ) {
-			const convertedChildren = conversionApi.convertChildren( data.input, consumable, { context: data.context } );
+			const convertedChildren = conversionApi.convertChildren( data.input, consumable, data );
 
 			data.output = new ModelDocumentFragment( convertedChildren );
 		}
@@ -50,9 +50,16 @@ export function convertToModelFragment() {
  * @returns {Function} {@link engine.treeView.Text View text} converter.
  */
 export function convertText() {
-	return ( evt, data, consumable ) => {
-		if ( consumable.consume( data.input ) ) {
-			data.output = new ModelText( data.input.data );
+	return ( evt, data, consumable, conversionApi ) => {
+		const schemaQuery = {
+			name: '$text',
+			inside: data.context
+		};
+
+		if ( conversionApi.schema.check( schemaQuery ) ) {
+			if ( consumable.consume( data.input ) ) {
+				data.output = new ModelText( data.input.data );
+			}
 		}
 	};
 }

+ 9 - 7
packages/ckeditor5-engine/src/treecontroller/viewconversiondispatcher.js

@@ -47,11 +47,12 @@ import extend from '../../utils/lib/lodash/extend.js';
  *				inside: data.context
  *			};
  *
- *			if ( conversionApi.schema.checkQuery( schemaQuery ) ) {
+ *			if ( conversionApi.schema.check( schemaQuery ) ) {
  *				if ( !consumable.consume( data.input, { name: true } ) ) {
  *					// Before converting this paragraph's children we have to update their context by this paragraph.
- *					const context = data.context.concat( paragraph );
- *					const children = conversionApi.convertChildren( data.input, consumable, { context } );
+ *					data.context.push( paragraph );
+ *					const children = conversionApi.convertChildren( data.input, consumable, data );
+ *					data.context.pop();
  *					paragraph.appendChildren( children );
  *					data.output = paragraph;
  *				}
@@ -63,7 +64,7 @@ import extend from '../../utils/lib/lodash/extend.js';
  *			if ( consumable.consume( data.input, { name: true, attributes: [ 'href' ] } ) ) {
  *				// <a> element is inline and is represented by an attribute in the model.
  *				// This is why we are not updating `context` property.
- *				data.output = conversionApi.convertChildren( data.input, consumable, { context: data.context } );
+ *				data.output = conversionApi.convertChildren( data.input, consumable, data );
  *
  *				for ( let item of Range.createFrom( data.output ) ) {
  *					const schemaQuery = {
@@ -80,8 +81,9 @@ import extend from '../../utils/lib/lodash/extend.js';
  *		} );
  *
  *		// Fire conversion.
- *		// At the beginning, the context is empty because given `viewDocumentFragment` has no parent.
- *		viewDispatcher.convert( viewDocumentFragment, { context: [] } );
+ *		// 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, { context: [ '$root' ] } );
  *
  * Before each conversion process, `ViewConversionDispatcher` fires {@link engine.treeController.ViewConversionDispatcher.viewCleanup}
  * event which can be used to prepare tree view for conversion.
@@ -140,7 +142,7 @@ export default class ViewConversionDispatcher {
 	 * @see engine.treeController.ViewConversionApi#convertItem
 	 */
 	_convertItem( input, consumable, additionalData = {} ) {
-		const data = extend( additionalData, {
+		const data = extend( {}, additionalData, {
 			input: input,
 			output: null
 		} );

+ 2 - 1
packages/ckeditor5-engine/tests/treecontroller/advanced-converters.js

@@ -54,7 +54,8 @@ beforeEach( () => {
 	writer = new ViewWriter();
 
 	modelDispatcher = new ModelConversionDispatcher( { mapper, writer } );
-	viewDispatcher = new ViewConversionDispatcher();
+	// Schema is mocked up because we don't care about it in those tests.
+	viewDispatcher = new ViewConversionDispatcher( { schema: { check: () => true } } );
 
 	modelDispatcher.on( 'insert:$text', insertText() );
 	modelDispatcher.on( 'move', move() );

+ 30 - 7
packages/ckeditor5-engine/tests/treecontroller/view-to-model-converters.js

@@ -12,16 +12,21 @@ import ViewContainerElement from '/ckeditor5/engine/treeview/containerelement.js
 import ViewDocumentFragment from '/ckeditor5/engine/treeview/documentfragment.js';
 import ViewText from '/ckeditor5/engine/treeview/text.js';
 
+import ModelSchema from '/ckeditor5/engine/treemodel/schema.js';
 import ModelDocumentFragment from '/ckeditor5/engine/treemodel/documentfragment.js';
 import ModelElement from '/ckeditor5/engine/treemodel/element.js';
 import ModelText from '/ckeditor5/engine/treemodel/text.js';
 
 import { convertToModelFragment, convertText } from '/ckeditor5/engine/treecontroller/view-to-model-converters.js';
 
-let dispatcher;
+let dispatcher, schema, objWithContext;
 
 beforeEach( () => {
-	dispatcher = new ViewConversionDispatcher();
+	schema = new ModelSchema();
+	schema.registerItem( 'paragraph', '$block' );
+	schema.allow( { name: '$text', inside: '$root' } );
+	objWithContext = { context: [ '$root' ] };
+	dispatcher = new ViewConversionDispatcher( { schema } );
 } );
 
 describe( 'convertText', () => {
@@ -30,7 +35,7 @@ describe( 'convertText', () => {
 
 		dispatcher.on( 'text', convertText() );
 
-		const result = dispatcher.convert( viewText );
+		const result = dispatcher.convert( viewText, objWithContext );
 
 		expect( result ).to.be.instanceof( ModelText );
 		expect( result.text ).to.equal( 'foobar' );
@@ -48,11 +53,26 @@ describe( 'convertText', () => {
 			}
 		} );
 
-		const result = dispatcher.convert( viewText );
+		const result = dispatcher.convert( viewText, objWithContext );
 
 		expect( result ).to.be.instanceof( ModelText );
 		expect( result.text ).to.equal( 'foo****ba****r' );
 	} );
+
+	it( 'should not convert text if it is wrong with schema', () => {
+		schema.disallow( { name: '$text', inside: '$root' } );
+
+		const viewText = new ViewText( 'foobar' );
+		dispatcher.on( 'text', convertText() );
+
+		let result = dispatcher.convert( viewText, objWithContext );
+
+		expect( result ).to.be.null;
+
+		result = dispatcher.convert( viewText, { context: [ '$block' ] } );
+		expect( result ).to.be.instanceof( ModelText );
+		expect( result.text ).to.equal( 'foobar' );
+	} );
 } );
 
 describe( 'convertToModelFragment', () => {
@@ -68,7 +88,7 @@ describe( 'convertToModelFragment', () => {
 		dispatcher.on( 'element', convertToModelFragment() );
 		dispatcher.on( 'documentFragment', convertToModelFragment() );
 
-		const result = dispatcher.convert( viewFragment );
+		const result = dispatcher.convert( viewFragment, objWithContext );
 
 		expect( result ).to.be.instanceof( ModelDocumentFragment );
 		expect( result.getChildCount() ).to.equal( 6 );
@@ -91,11 +111,14 @@ describe( 'convertToModelFragment', () => {
 		dispatcher.on( 'element:p', ( evt, data, consumable, conversionApi ) => {
 			if ( consumable.consume( data.input, { name: true } ) ) {
 				data.output = new ModelElement( 'paragraph' );
-				data.output.appendChildren( conversionApi.convertChildren( data.input, consumable ) );
+
+				data.context.push( data.output );
+				data.output.appendChildren( conversionApi.convertChildren( data.input, consumable, data ) );
+				data.context.pop();
 			}
 		} );
 
-		const result = dispatcher.convert( viewP );
+		const result = dispatcher.convert( viewP, objWithContext );
 
 		expect( result ).to.be.instanceof( ModelElement );
 		expect( result.name ).to.equal( 'paragraph' );