Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit 2210696

Browse files
authored
Fix: Added a proper check for name-only view matcher in attribute upcast converters. Closes #1786.
2 parents 34e7652 + a762b48 commit 2210696

File tree

2 files changed

+41
-22
lines changed

2 files changed

+41
-22
lines changed

src/conversion/upcasthelpers.js

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ function upcastElementToElement( config ) {
405405

406406
const converter = prepareToElementConverter( config );
407407

408-
const elementName = getViewElementNameFromConfig( config );
408+
const elementName = getViewElementNameFromConfig( config.view );
409409
const eventName = elementName ? 'element:' + elementName : 'element';
410410

411411
return dispatcher => {
@@ -431,7 +431,7 @@ function upcastElementToAttribute( config ) {
431431

432432
const converter = prepareToAttributeConverter( config, false );
433433

434-
const elementName = getViewElementNameFromConfig( config );
434+
const elementName = getViewElementNameFromConfig( config.view );
435435
const eventName = elementName ? 'element:' + elementName : 'element';
436436

437437
return dispatcher => {
@@ -493,15 +493,15 @@ function upcastElementToMarker( config ) {
493493
// Helper function for from-view-element conversion. Checks if `config.view` directly specifies converted view element's name
494494
// and if so, returns it.
495495
//
496-
// @param {Object} config Conversion config.
496+
// @param {Object} config Conversion view config.
497497
// @returns {String|null} View element name or `null` if name is not directly set.
498-
function getViewElementNameFromConfig( config ) {
499-
if ( typeof config.view == 'string' ) {
500-
return config.view;
498+
function getViewElementNameFromConfig( viewConfig ) {
499+
if ( typeof viewConfig == 'string' ) {
500+
return viewConfig;
501501
}
502502

503-
if ( typeof config.view == 'object' && typeof config.view.name == 'string' ) {
504-
return config.view.name;
503+
if ( typeof viewConfig == 'object' && typeof viewConfig.name == 'string' ) {
504+
return viewConfig.name;
505505
}
506506

507507
return null;
@@ -684,7 +684,7 @@ function prepareToAttributeConverter( config, shallow ) {
684684
return;
685685
}
686686

687-
if ( onlyViewNameIsDefined( config ) ) {
687+
if ( onlyViewNameIsDefined( config.view, data.viewItem ) ) {
688688
match.match.name = true;
689689
} else {
690690
// Do not test or consume `name` consumable.
@@ -714,14 +714,17 @@ function prepareToAttributeConverter( config, shallow ) {
714714

715715
// Helper function that checks if element name should be consumed in attribute converters.
716716
//
717-
// @param {Object} config Conversion config.
717+
// @param {Object} config Conversion view config.
718718
// @returns {Boolean}
719-
function onlyViewNameIsDefined( config ) {
720-
if ( typeof config.view == 'object' && !getViewElementNameFromConfig( config ) ) {
719+
function onlyViewNameIsDefined( viewConfig, viewItem ) {
720+
// https://github.com/ckeditor/ckeditor5-engine/issues/1786
721+
const configToTest = typeof viewConfig == 'function' ? viewConfig( viewItem ) : viewConfig;
722+
723+
if ( typeof configToTest == 'object' && !getViewElementNameFromConfig( configToTest ) ) {
721724
return false;
722725
}
723726

724-
return !config.view.classes && !config.view.attributes && !config.view.styles;
727+
return !configToTest.classes && !configToTest.attributes && !configToTest.styles;
725728
}
726729

727730
// Helper function for to-model-attribute converter. Sets model attribute on given range. Checks {@link module:engine/model/schema~Schema}

tests/conversion/conversion.js

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,14 @@ describe( 'Conversion', () => {
301301
} );
302302

303303
it( 'config.view is an object with upcastAlso defined', () => {
304+
schema.extend( '$text', {
305+
allowAttributes: [ 'bold', 'xBold' ]
306+
} );
307+
conversion.attributeToElement( {
308+
model: 'xBold',
309+
view: 'x-bold'
310+
} );
311+
304312
conversion.attributeToElement( {
305313
model: 'bold',
306314
view: 'strong',
@@ -310,22 +318,18 @@ describe( 'Conversion', () => {
310318
name: 'span',
311319
classes: 'bold'
312320
},
313-
{
314-
name: 'span',
315-
styles: {
316-
'font-weight': 'bold'
317-
}
318-
},
319321
viewElement => {
320322
const fontWeight = viewElement.getStyle( 'font-weight' );
321323

322-
if ( viewElement.is( 'span' ) && fontWeight && /\d+/.test( fontWeight ) && Number( fontWeight ) > 500 ) {
324+
if ( fontWeight == 'bold' || Number( fontWeight ) > 500 ) {
323325
return {
324-
name: true,
325326
styles: [ 'font-weight' ]
326327
};
327328
}
328-
}
329+
},
330+
// Duplicates the `x-bold` from above to test if only one attribute would be converted.
331+
// It should not convert to both bold & x-bold.
332+
viewElement => viewElement.is( 'x-bold' ) ? { name: 'x-bold' } : null
329333
]
330334
} );
331335

@@ -363,6 +367,18 @@ describe( 'Conversion', () => {
363367
'<paragraph><$text bold="true">Foo</$text></paragraph>',
364368
'<p><strong>Foo</strong></p>'
365369
);
370+
371+
test(
372+
'<p style="font-weight: 600;">Foo</p>',
373+
'<paragraph><$text bold="true">Foo</$text></paragraph>',
374+
'<p><strong>Foo</strong></p>'
375+
);
376+
377+
test(
378+
'<p><x-bold style="font-wieght:bold">Foo</x-bold></p>',
379+
'<paragraph><$text xBold="true">Foo</$text></paragraph>',
380+
'<p><x-bold>Foo</x-bold></p>'
381+
);
366382
} );
367383

368384
it( 'model attribute value is enumerable', () => {

0 commit comments

Comments
 (0)