@@ -302,7 +302,7 @@ export default class Renderer {
302
302
* @param {module:engine/view/node~Node } viewElement The view element which children mappings will be updated.
303
303
*/
304
304
_updateChildrenMappings ( viewElement ) {
305
- // We do not perform any operations on DOM here so there is no need to bind view element or convert its' children.
305
+ // We do not perform any operations on DOM here so there is no need to bind view element or convert its children.
306
306
const diff = this . _diffElementChildren ( viewElement , { bind : false , withChildren : false } ) ;
307
307
308
308
if ( diff ) {
@@ -317,8 +317,23 @@ export default class Renderer {
317
317
const viewChild = viewElement . getChild ( insertIndex ) ;
318
318
319
319
if ( viewChild ) {
320
+ // Because we replace previous view element mapping with the new one, the corresponding DOM element
321
+ // will not be rerendered. The new view element may have different attributes than the old one.
322
+ // Its corresponding DOM element will not be rerendered so new attributes will not be present in a DOM.
323
+ // Such situation may take place if only previous view element was added to `this.markedAttributes`
324
+ // or none of elements were added (relying on 'this._updateChildren()' which by rerendering the element
325
+ // also rerenders its attributes). See #1427 for more detailed case study.
326
+ // It may also happen that 'oldViewElement' mapping is not present since its parent mapping
327
+ // was removed ('domConverter.unbindDomElement' also unbinds children mappings).
328
+ const oldViewChild = this . domConverter . mapDomToView ( diff . actualDomChildren [ deleteIndex ] ) ;
329
+ if ( ! oldViewChild || oldViewChild && ! oldViewChild . isSimilar ( viewChild ) ) {
330
+ this . markedAttributes . add ( viewChild ) ;
331
+ }
332
+
333
+ // Remap 'DomConverter' bindings.
320
334
this . domConverter . unbindDomElement ( diff . actualDomChildren [ deleteIndex ] ) ;
321
335
this . domConverter . bindElements ( diff . actualDomChildren [ deleteIndex ] , viewChild ) ;
336
+
322
337
// View element may have children which needs to be updated, but are not marked, mark them to update.
323
338
this . markedChildren . add ( viewChild ) ;
324
339
}
@@ -537,6 +552,15 @@ export default class Renderer {
537
552
*/
538
553
_updateAttrs ( viewElement ) {
539
554
const domElement = this . domConverter . mapViewToDom ( viewElement ) ;
555
+
556
+ if ( ! domElement ) {
557
+ // If there is no `domElement` it means that 'viewElement' is outdated as its mapping was updated
558
+ // in 'this._updateChildrenMappings()'. There is no need to process it as new view element which
559
+ // replaced old 'viewElement' mapping was also added to 'this.markedAttributes'
560
+ // in 'this._updateChildrenMappings()' so it will be processed separately.
561
+ return ;
562
+ }
563
+
540
564
const domAttrKeys = Array . from ( domElement . attributes ) . map ( attr => attr . name ) ;
541
565
const viewAttrKeys = viewElement . getAttributeKeys ( ) ;
542
566
0 commit comments