8
0
Pārlūkot izejas kodu

Changed: unified API by renaming engine.treeController.ViewConverterBuilder#toAttributes to #toAttribute

Szymon Cofalik 9 gadi atpakaļ
vecāks
revīzija
6e13f2ffbb

+ 1 - 1
packages/ckeditor5-engine/src/treecontroller/model-converter-builder.js

@@ -187,7 +187,7 @@ class ModelConverterBuilder {
 	 * Registers what view attribute will be created by converter. Keep in mind, that only model attribute to
 	 * view attribute conversion is supported.
 	 *
-	 * Method accepts various ways of providing how the view element will be created:
+	 * Method accepts various ways of providing how the view attribute will be created:
 	 *
 	 * * for no passed parameter, attribute key and value will be converted 1-to-1 to view attribute,
 	 * * if you pass one `string`, it will be used as new attribute key while attribute value will be copied,

+ 16 - 17
packages/ckeditor5-engine/src/treecontroller/view-converter-builder.js

@@ -286,18 +286,19 @@ class ViewConverterBuilder {
 	/**
 	 * Registers what model attribute will be created by converter.
 	 *
-	 * Method accepts two ways of providing what kind of model attribute will be created. You can pass `object` which
-	 * keys will be translated to model attributes keys and values to model attributes values or you can pass a function which
-	 * will return such object. If you provide creator function, it will be passed converted view element as first and only parameter.
+	 * Method accepts two ways of providing what kind of model attribute will be created. You can either pass two strings
+	 * representing attribute key and attribute value or a function that returns an object with `key` and `value` properties.
+	 * If you provide creator function, it will be passed converted view element as first and only parameter.
 	 *
-	 *		BuildViewConverterFor( dispatcher ).fromAttribute( 'style', { 'font-weight': 'bold' } ).toAttributes( { bold: true } );
+	 *		BuildViewConverterFor( dispatcher ).fromAttribute( 'style', { 'font-weight': 'bold' } ).toAttribute( 'bold', true );
 	 *		BuildViewConverterFor( dispatcher )
 	 *			.fromAttribute( 'class' )
-	 *			.toAttributes( ( viewElement ) => ( { class: viewElement.getAttribute( 'class' ) } ) );
+	 *			.toAttribute( ( viewElement ) => ( { key: 'class', value: viewElement.getAttribute( 'class' ) } ) );
 	 *
-	 * @param {Object|Function} attributes Object with model attributes or creator function.
+	 * @param {String|Function} keyOrCreator Attribute key or a creator function.
+	 * @param {String} [value] Attribute value. Required if `keyOrCreator` is a `string`. Ignored otherwise.
 	 */
-	toAttributes( attributes ) {
+	toAttribute( keyOrCreator, value ) {
 		const eventCallbackGen = function( from ) {
 			return ( evt, data, consumable, conversionApi ) => {
 				// There is one callback for all patterns in the matcher.
@@ -322,11 +323,11 @@ class ViewConverterBuilder {
 						data.output = conversionApi.convertChildren( data.input, consumable, data );
 					}
 
-					// Use attributes object creator function, if provided.
-					const modelAttributes = attributes instanceof Function ? attributes( data.input ) : attributes;
+					// Use attribute creator function, if provided.
+					let attribute = keyOrCreator instanceof Function ? keyOrCreator( data.input ) : { key: keyOrCreator, value: value };
 
-					// Set attributes on current `output`. `Schema` is checked inside this helper function.
-					setAttributesOn( data.output, modelAttributes, data, conversionApi );
+					// Set attribute on current `output`. `Schema` is checked inside this helper function.
+					setAttributeOn( data.output, attribute, data, conversionApi );
 
 					// Prevent multiple conversion if there are other correct matches.
 					break;
@@ -364,17 +365,17 @@ class ViewConverterBuilder {
 }
 
 // Helper function that sets given attributes on given `engine.treeModel.Item` or `engine.treeModel.DocumentFragment`.
-function setAttributesOn( toChange, attributes, data, conversionApi ) {
+function setAttributeOn( toChange, attribute, data, conversionApi ) {
 	if ( utils.isIterable( toChange ) ) {
 		for ( let node of toChange ) {
-			setAttributesOn( node, attributes, data, conversionApi );
+			setAttributeOn( node, attribute, data, conversionApi );
 		}
 
 		return;
 	}
 
 	// TODO: Make it more sane after .getAttributeKeys() is available for ModelElement.
-	const keys = Array.from( toChange.getAttributes() ).map( ( attribute ) => attribute[ 0 ] ).concat( Object.keys( attributes ) );
+	const keys = Array.from( toChange.getAttributes() ).map( ( attribute ) => attribute[ 0 ] ).concat( attribute.key );
 
 	const schemaQuery = {
 		name: toChange.name || '$text',
@@ -383,9 +384,7 @@ function setAttributesOn( toChange, attributes, data, conversionApi ) {
 	};
 
 	if ( conversionApi.schema.check( schemaQuery ) ) {
-		for ( let key in attributes ) {
-			toChange.setAttribute( key, attributes[ key ] );
-		}
+		toChange.setAttribute( attribute.key, attribute.value );
 	}
 }
 

+ 14 - 25
packages/ckeditor5-engine/tests/treecontroller/view-converter-builder.js

@@ -116,7 +116,7 @@ describe( 'View converter builder', () => {
 	} );
 
 	it( 'should convert from view element to model attribute', () => {
-		BuildViewConverterFor( dispatcher ).fromElement( 'strong' ).toAttributes( { bold: true } );
+		BuildViewConverterFor( dispatcher ).fromElement( 'strong' ).toAttribute( 'bold', true );
 
 		const result = dispatcher.convert( new ViewAttributeElement( 'strong', null, new ViewText( 'foo' ) ), objWithContext );
 		modelRoot.appendChildren( result );
@@ -125,21 +125,10 @@ describe( 'View converter builder', () => {
 		expect( modelToString( modelRoot ) ).to.equal( '<$root><$text bold="true">foo</$text></$root>' );
 	} );
 
-	it( 'should convert from view element to multiple model attributes', () => {
-		// Very theoretical example...
-		BuildViewConverterFor( dispatcher ).fromElement( 'i' ).toAttributes( { italic: true, style: 'italic' } );
-
-		const result = dispatcher.convert( new ViewAttributeElement( 'i', null, new ViewText( 'foo' ) ), objWithContext );
-		modelRoot.appendChildren( result );
-
-		// Have to check root because result is a ModelText.
-		expect( modelToString( modelRoot ) ).to.equal( '<$root><$text italic="true" style="italic">foo</$text></$root>' );
-	} );
-
 	it( 'should convert from view element to model attributes using creator function', () => {
 		BuildViewConverterFor( dispatcher )
 			.fromElement( 'a' )
-			.toAttributes( ( viewElement ) => ( { linkHref: viewElement.getAttribute( 'href' ) } ) );
+			.toAttribute( ( viewElement ) => ( { key: 'linkHref', value: viewElement.getAttribute( 'href' ) } ) );
 
 		const result = dispatcher.convert( new ViewAttributeElement( 'a', { href: 'foo.html' }, new ViewText( 'foo' ) ), objWithContext );
 		modelRoot.appendChildren( result );
@@ -153,7 +142,7 @@ describe( 'View converter builder', () => {
 
 		BuildViewConverterFor( dispatcher )
 			.fromAttribute( 'class' )
-			.toAttributes( ( viewElement ) => ( { class: viewElement.getAttribute( 'class' ) } ) );
+			.toAttribute( ( viewElement ) => ( { key: 'class', value: viewElement.getAttribute( 'class' ) } ) );
 
 		const result = dispatcher.convert( new ViewContainerElement( 'p', { class: 'myClass' }, new ViewText( 'foo' ) ), objWithContext );
 		modelRoot.appendChildren( result );
@@ -165,8 +154,8 @@ describe( 'View converter builder', () => {
 		dispatcher.on( 'documentFragment', convertToModelFragment() );
 
 		BuildViewConverterFor( dispatcher ).fromElement( 'p' ).toElement( 'paragraph' );
-		BuildViewConverterFor( dispatcher ).fromAttribute( 'class', 'important' ).toAttributes( { important: true } );
-		BuildViewConverterFor( dispatcher ).fromAttribute( 'class', 'theme-nice' ).toAttributes( { theme: 'nice' } );
+		BuildViewConverterFor( dispatcher ).fromAttribute( 'class', 'important' ).toAttribute( 'important', true );
+		BuildViewConverterFor( dispatcher ).fromAttribute( 'class', 'theme-nice' ).toAttribute( 'theme', 'nice' );
 
 		const viewStructure = new ViewDocumentFragment( [
 			new ViewContainerElement( 'p', { class: 'important' }, new ViewText( 'foo' ) ),
@@ -187,7 +176,7 @@ describe( 'View converter builder', () => {
 			.fromElement( 'b' )
 			.fromAttribute( 'class', 'bold' )
 			.fromAttribute( 'style', { 'font-weight': 'bold' } )
-			.toAttributes( { bold: true } );
+			.toAttribute( 'bold', true );
 
 		const viewElement = new ViewContainerElement( 'p', null, [
 			new ViewAttributeElement( 'strong', null, new ViewText( 'aaa' ) ),
@@ -260,7 +249,7 @@ describe( 'View converter builder', () => {
 		// This time without name so default span converter will convert children.
 		BuildViewConverterFor( dispatcher )
 			.from( { class: 'megatron', attribute: { head: 'megatron', body: 'megatron', legs: 'megatron' } } )
-			.toAttributes( { transformer: 'megatron' } );
+			.toAttribute( 'transformer', 'megatron' );
 
 		let viewElement = new ViewContainerElement(
 			'span',
@@ -274,10 +263,10 @@ describe( 'View converter builder', () => {
 		expect( modelToString( result ) ).to.equal( '<span transformer="megatron">foo</span>' );
 	} );
 
-	it( 'should set different priorities for `toElement` and `toAttributes` conversion', () => {
+	it( 'should set different priorities for `toElement` and `toAttribute` conversion', () => {
 		BuildViewConverterFor( dispatcher )
 			.fromAttribute( 'class' )
-			.toAttributes( ( viewElement ) => ( { class: viewElement.getAttribute( 'class' ) } ) );
+			.toAttribute( ( viewElement ) => ( { key: 'class', value: viewElement.getAttribute( 'class' ) } ) );
 		BuildViewConverterFor( dispatcher ).fromElement( 'p' ).toElement( 'paragraph' );
 
 		let result = dispatcher.convert( new ViewContainerElement( 'p', { class: 'myClass' }, new ViewText( 'foo' ) ), objWithContext );
@@ -291,7 +280,7 @@ describe( 'View converter builder', () => {
 		BuildViewConverterFor( dispatcher ).fromElement( 'p' ).toElement( 'paragraph' );
 		BuildViewConverterFor( dispatcher )
 			.fromAttribute( 'class' )
-			.toAttributes( ( viewElement ) => ( { class: viewElement.getAttribute( 'class' ) } ) );
+			.toAttribute( ( viewElement ) => ( { key: 'class', value: viewElement.getAttribute( 'class' ) } ) );
 
 		let result;
 
@@ -315,12 +304,12 @@ describe( 'View converter builder', () => {
 		// Converter (2).
 		BuildViewConverterFor( dispatcher )
 			.from( { name: 'p', class: 'decorated' } ).consuming( { class: 'decorated' } )
-			.toAttributes( { decorated: true } );
+			.toAttribute( 'decorated', true );
 
 		// Converter (3).
 		BuildViewConverterFor( dispatcher )
 			.fromAttribute( 'class', 'small' ).consuming( { class: 'small' } )
-			.toAttributes( { size: 'small' } );
+			.toAttribute( 'size', 'small' );
 
 		const viewElement = new ViewContainerElement( 'p', { class: 'decorated small' }, new ViewText( 'foo' ) );
 
@@ -337,7 +326,7 @@ describe( 'View converter builder', () => {
 		// Universal class converter, synonymous to .fromAttribute( 'class' ).
 		BuildViewConverterFor( dispatcher )
 			.from( new ViewMatcher( { class: /.*/ } ) )
-			.toAttributes( ( viewElement ) => ( { class: viewElement.getAttribute( 'class' ) } ) );
+			.toAttribute( ( viewElement ) => ( { key: 'class', value: viewElement.getAttribute( 'class' ) } ) );
 
 		// Universal element converter.
 		BuildViewConverterFor( dispatcher )
@@ -355,7 +344,7 @@ describe( 'View converter builder', () => {
 	} );
 
 	it( 'should filter out structure that is wrong with schema', () => {
-		BuildViewConverterFor( dispatcher ).fromElement( 'strong' ).toAttributes( { bold: true } );
+		BuildViewConverterFor( dispatcher ).fromElement( 'strong' ).toAttribute( 'bold', true );
 		BuildViewConverterFor( dispatcher ).fromElement( 'div' ).toElement( 'div' );
 		BuildViewConverterFor( dispatcher ).fromElement( 'p' ).toElement( 'paragraph' );