@@ -74,6 +74,14 @@ export function upcastElementToElement( config ) {
7474 * This conversion results in setting an attribute on a model node. For example, view `<strong>Foo</strong>` becomes
7575 * `Foo` {@link module:engine/model/text~Text model text node} with `bold` attribute set to `true`.
7676 *
77+ * This helper is meant to set a model attribute on all the elements that are inside the converted element:
78+ *
79+ * <strong>Foo</strong> --> <strong><p>Foo</p></strong> --> <paragraph><$text bold="true">Foo</$text></paragraph>
80+ *
81+ * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).
82+ * Even though `<strong>` is over `<p>` element, `bold="true"` was added to the text. See
83+ * {@link module:engine/model/upcast-converters~upcastAttributeToAttribute} for comparison.
84+ *
7785 * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.
7886 *
7987 * upcastElementToAttribute( { view: 'strong', model: 'bold' } );
@@ -138,7 +146,7 @@ export function upcastElementToAttribute( config ) {
138146
139147 _normalizeModelAttributeConfig ( config ) ;
140148
141- const converter = _prepareToAttributeConverter ( config ) ;
149+ const converter = _prepareToAttributeConverter ( config , false ) ;
142150
143151 const elementName = _getViewElementNameFromConfig ( config ) ;
144152 const eventName = elementName ? 'element:' + elementName : 'element' ;
@@ -154,6 +162,19 @@ export function upcastElementToAttribute( config ) {
154162 * This conversion results in setting an attribute on a model node. For example, view `<img src="foo.jpg"></img>` becomes
155163 * `<image source="foo.jpg"></image>` in the model.
156164 *
165+ * This helper is meant to convert view attributes from view elements which got converted to the model, so the view attribute
166+ * is set only on the corresponding model node:
167+ *
168+ * <div class="dark"><div>foo</div></div> --> <div dark="true"><div>foo</div></div>
169+ *
170+ * Above, `class="dark"` attribute is added only to the `<div>` elements that has it. This is in contrary to
171+ * {@link module:engine/conversion/upcast-converters~upcastElementToAttribute} which sets attributes for all the children in the model:
172+ *
173+ * <strong>Foo</strong> --> <strong><p>Foo</p></strong> --> <paragraph><$text bold="true">Foo</$text></paragraph>
174+ *
175+ * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).
176+ * Even though `<strong>` is over `<p>` element, `bold="true"` was added to the text.
177+ *
157178 * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.
158179 *
159180 * upcastAttributeToAttribute( { view: 'src', model: 'source' } );
@@ -223,7 +244,7 @@ export function upcastAttributeToAttribute( config ) {
223244
224245 _normalizeModelAttributeConfig ( config , viewKey ) ;
225246
226- const converter = _prepareToAttributeConverter ( config ) ;
247+ const converter = _prepareToAttributeConverter ( config , true ) ;
227248
228249 return dispatcher => {
229250 dispatcher . on ( 'element' , converter , { priority : config . converterPriority || 'low' } ) ;
@@ -442,9 +463,9 @@ function _normalizeModelAttributeConfig( config, viewAttributeKeyToCopy = null )
442463//
443464// @param {String } modelAttributeKey The key of the model attribute to set on a model node.
444465// @param {Object|Array.<Object> } config Conversion configuration. It is possible to provide multiple configurations in an array.
445- // @param {Boolean } consumeName If set to `true` converter will try to consume name. If set to `false` converter will not try to
446- // consume name. This flag overwrites parameter returned by `Matcher#match` .
447- function _prepareToAttributeConverter ( config ) {
466+ // @param {Boolean } shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set
467+ // on all elements in the range .
468+ function _prepareToAttributeConverter ( config , shallow ) {
448469 const matcher = new Matcher ( config . view ) ;
449470
450471 return ( evt , data , conversionApi ) => {
@@ -483,7 +504,7 @@ function _prepareToAttributeConverter( config ) {
483504 }
484505
485506 // Set attribute on current `output`. `Schema` is checked inside this helper function.
486- const attributeWasSet = _setAttributeOn ( data . modelRange , { key : modelKey , value : modelValue } , conversionApi ) ;
507+ const attributeWasSet = _setAttributeOn ( data . modelRange , { key : modelKey , value : modelValue } , shallow , conversionApi ) ;
487508
488509 if ( attributeWasSet ) {
489510 conversionApi . consumable . consume ( data . viewItem , match . match ) ;
@@ -509,12 +530,14 @@ function _onlyViewNameIsDefined( config ) {
509530// @param {module:engine/model/range~Range } modelRange Model range on which attribute should be set.
510531// @param {Object } modelAttribute Model attribute to set.
511532// @param {Object } conversionApi Conversion API.
533+ // @param {Boolean } shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set
534+ // on all elements in the range.
512535// @returns {Boolean } `true` if attribute was set on at least one node from given `modelRange`.
513- function _setAttributeOn ( modelRange , modelAttribute , conversionApi ) {
536+ function _setAttributeOn ( modelRange , modelAttribute , shallow , conversionApi ) {
514537 let result = false ;
515538
516539 // Set attribute on each item in range according to Schema.
517- for ( const node of Array . from ( modelRange . getItems ( { shallow : true } ) ) ) {
540+ for ( const node of Array . from ( modelRange . getItems ( { shallow } ) ) ) {
518541 if ( conversionApi . schema . checkAttribute ( node , modelAttribute . key ) ) {
519542 conversionApi . writer . setAttribute ( modelAttribute . key , modelAttribute . value , node ) ;
520543
0 commit comments