Browse Source

Fixed attributes rendering for replaced elements.

Krzysztof Krztoń 7 years ago
parent
commit
ab56a4fc66
1 changed files with 25 additions and 1 deletions
  1. 25 1
      packages/ckeditor5-engine/src/view/renderer.js

+ 25 - 1
packages/ckeditor5-engine/src/view/renderer.js

@@ -302,7 +302,7 @@ export default class Renderer {
 	 * @param {module:engine/view/node~Node} viewElement The view element which children mappings will be updated.
 	 */
 	_updateChildrenMappings( viewElement ) {
-		// We do not perform any operations on DOM here so there is no need to bind view element or convert its' children.
+		// We do not perform any operations on DOM here so there is no need to bind view element or convert its children.
 		const diff = this._diffElementChildren( viewElement, { bind: false, withChildren: false } );
 
 		if ( diff ) {
@@ -317,8 +317,23 @@ export default class Renderer {
 						const viewChild = viewElement.getChild( insertIndex );
 
 						if ( viewChild ) {
+							// Because we replace previous view element mapping with the new one, the corresponding DOM element
+							// will not be rerendered. The new view element may have different attributes than the old one.
+							// Its corresponding DOM element will not be rerendered so new attributes will not be present in a DOM.
+							// Such situation may take place if only previous view element was added to `this.markedAttributes`
+							// or none of elements were added (relying on 'this._updateChildren()' which by rerendering the element
+							// also rerenders its attributes). See #1427 for more detailed case study.
+							// It may also happen that 'oldViewElement' mapping is not present since its parent mapping
+							// was removed ('domConverter.unbindDomElement' also unbinds children mappings).
+							const oldViewChild = this.domConverter.mapDomToView( diff.actualDomChildren[ deleteIndex ] );
+							if ( !oldViewChild || oldViewChild && !oldViewChild.isSimilar( viewChild ) ) {
+								this.markedAttributes.add( viewChild );
+							}
+
+							// Remap 'DomConverter' bindings.
 							this.domConverter.unbindDomElement( diff.actualDomChildren[ deleteIndex ] );
 							this.domConverter.bindElements( diff.actualDomChildren[ deleteIndex ], viewChild );
+
 							// View element may have children which needs to be updated, but are not marked, mark them to update.
 							this.markedChildren.add( viewChild );
 						}
@@ -537,6 +552,15 @@ export default class Renderer {
 	 */
 	_updateAttrs( viewElement ) {
 		const domElement = this.domConverter.mapViewToDom( viewElement );
+
+		if ( !domElement ) {
+			// If there is no `domElement` it means that 'viewElement' is outdated as its mapping was updated
+			// in 'this._updateChildrenMappings()'. There is no need to process it as new view element which
+			// replaced old 'viewElement' mapping was also added to 'this.markedAttributes'
+			// in 'this._updateChildrenMappings()' so it will be processed separately.
+			return;
+		}
+
 		const domAttrKeys = Array.from( domElement.attributes ).map( attr => attr.name );
 		const viewAttrKeys = viewElement.getAttributeKeys();