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

Do not run 'AttributeToAttribute' conversion on 'TextProxy'.

Krzysztof Krztoń 7 лет назад
Родитель
Сommit
14b51b2ddf

+ 6 - 0
packages/ckeditor5-engine/src/conversion/downcast-converters.js

@@ -685,6 +685,12 @@ export function changeAttribute( attributeCreator ) {
 		const viewElement = conversionApi.mapper.toViewElement( data.item );
 		const viewElement = conversionApi.mapper.toViewElement( data.item );
 		const viewWriter = conversionApi.writer;
 		const viewWriter = conversionApi.writer;
 
 
+		// If model item cannot be mapped to view element, it means item is not an `Element` instance (it is a `TextProxy`).
+		// Only elements can have attributes in a view so do not proceed for anything else (see #1587).
+		if ( !viewElement ) {
+			return;
+		}
+
 		// First remove the old attribute if there was one.
 		// First remove the old attribute if there was one.
 		if ( data.attributeOldValue !== null && oldAttribute ) {
 		if ( data.attributeOldValue !== null && oldAttribute ) {
 			if ( oldAttribute.key == 'class' ) {
 			if ( oldAttribute.key == 'class' ) {

+ 43 - 0
packages/ckeditor5-engine/tests/conversion/downcast-converters.js

@@ -460,6 +460,49 @@ describe( 'downcast-helpers', () => {
 
 
 			expectResult( '<img class="styled-pull-out"></img>' );
 			expectResult( '<img class="styled-pull-out"></img>' );
 		} );
 		} );
+
+		// #1587
+		it( 'config.view and config.model as strings in generic conversion (elements only)', () => {
+			conversion.for( 'downcast' ).add( downcastElementToElement( { model: 'paragraph', view: 'p' } ) );
+
+			conversion.for( 'downcast' ).add( downcastAttributeToAttribute( { model: 'test', view: 'test' } ) );
+
+			model.change( writer => {
+				writer.insertElement( 'paragraph', { test: '1' }, modelRoot, 0 );
+				writer.insertElement( 'paragraph', { test: '2' }, modelRoot, 1 );
+			} );
+
+			expectResult( '<p test="1"></p><p test="2"></p>' );
+
+			model.change( writer => {
+				writer.removeAttribute( 'test', modelRoot.getChild( 1 ) );
+			} );
+
+			expectResult( '<p test="1"></p><p></p>' );
+		} );
+
+		// #1587
+		it( 'config.view and config.model as strings in generic conversion (elements + text)', () => {
+			conversion.for( 'downcast' ).add( downcastElementToElement( { model: 'paragraph', view: 'p' } ) );
+
+			conversion.for( 'downcast' ).add( downcastAttributeToAttribute( { model: 'test', view: 'test' } ) );
+
+			model.change( writer => {
+				writer.insertElement( 'paragraph', modelRoot, 0 );
+				writer.insertElement( 'paragraph', { test: '1' }, modelRoot, 1 );
+
+				writer.insertText( 'Foo', { test: '2' }, modelRoot.getChild( 0 ), 0 );
+				writer.insertText( 'Bar', { test: '3' }, modelRoot.getChild( 1 ), 0 );
+			} );
+
+			expectResult( '<p>Foo</p><p test="1">Bar</p>' );
+
+			model.change( writer => {
+				writer.removeAttribute( 'test', modelRoot.getChild( 1 ) );
+			} );
+
+			expectResult( '<p>Foo</p><p>Bar</p>' );
+		} );
 	} );
 	} );
 
 
 	describe( 'downcastMarkerToElement', () => {
 	describe( 'downcastMarkerToElement', () => {