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

Commit 9b95a8a

Browse files
author
Piotr Jasiun
authored
Merge pull request #1568 from ckeditor/t/1560-c
Other: Always update attributes of reused elements while rendering. Closes #1560.
2 parents 6619a1f + 3a2854e commit 9b95a8a

File tree

2 files changed

+39
-18
lines changed

2 files changed

+39
-18
lines changed

src/view/renderer.js

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -294,30 +294,23 @@ export default class Renderer {
294294
* @param {Node} domElement The DOM element representing the given view element.
295295
*/
296296
_updateElementMappings( viewElement, domElement ) {
297-
// Because we replace new view element mapping with the existing one, the corresponding DOM element
298-
// will not be rerendered. The new view element may have different attributes than the previous one.
299-
// Since its corresponding DOM element will not be rerendered, new attributes will not be added
300-
// to the DOM, so we need to mark it here to make sure its attributes gets updated.
301-
// Such situations may happen if only new view element was added to `this.markedAttributes`
302-
// or none of the elements were added (relying on 'this._updateChildren()' which by rerendering the element
303-
// also rerenders its attributes). See #1427 for more detailed case study.
304-
const newViewChild = this.domConverter.mapDomToView( domElement );
305-
306-
// It may also happen that 'newViewChild' mapping is not present since its parent mapping
307-
// was already removed (the 'domConverter.unbindDomElement()' method also unbinds children
308-
// mappings) so we also check for '!newViewChild'.
309-
// Also check if new element ('newViewChild') was marked to have its attributes rerenderd,
310-
// if so, marked reused view element too (#1560).
311-
if ( !newViewChild || newViewChild && !newViewChild.isSimilar( viewElement ) || this.markedAttributes.has( newViewChild ) ) {
312-
this.markedAttributes.add( viewElement );
313-
}
314-
315297
// Remap 'DomConverter' bindings.
316298
this.domConverter.unbindDomElement( domElement );
317299
this.domConverter.bindElements( domElement, viewElement );
318300

319301
// View element may have children which needs to be updated, but are not marked, mark them to update.
320302
this.markedChildren.add( viewElement );
303+
304+
// Because we replace new view element mapping with the existing one, the corresponding DOM element
305+
// will not be rerendered. The new view element may have different attributes than the previous one.
306+
// Since its corresponding DOM element will not be rerendered, new attributes will not be added
307+
// to the DOM, so we need to mark it here to make sure its attributes gets updated. See #1427 for more
308+
// detailed case study.
309+
// Also there are cases where replaced element is removed from the view structure and then has
310+
// its attributes changed or removed. In such cases the element will not be present in `markedAttributes`
311+
// and also may be the same (`element.isSimilar()`) as the reused element not having its attributes updated.
312+
// To prevent such situations we always mark reused element to have its attributes rerenderd (#1560).
313+
this.markedAttributes.add( viewElement );
321314
}
322315

323316
/**

tests/view/renderer.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3100,6 +3100,34 @@ describe( 'Renderer', () => {
31003100

31013101
expect( domRoot.innerHTML ).to.equal( '<h1>h1</h1><p class="cke-test1">p</p><p>p2</p>' );
31023102
} );
3103+
3104+
it( 'should rerender element if it was removed and have its attributes removed after', () => {
3105+
const writer = new DowncastWriter();
3106+
3107+
// 1. Setup initial view/DOM.
3108+
viewRoot._appendChild( parse( '<container:p>1</container:p>' ) );
3109+
3110+
const viewP = viewRoot.getChild( 0 );
3111+
3112+
writer.setAttribute( 'data-placeholder', 'Body', viewP );
3113+
3114+
renderer.markToSync( 'children', viewRoot );
3115+
renderer.render();
3116+
3117+
expect( domRoot.innerHTML ).to.equal( '<p data-placeholder="Body">1</p>' );
3118+
3119+
// 2. Modify view.
3120+
viewRoot._removeChildren( 0, viewRoot.childCount );
3121+
3122+
writer.removeAttribute( 'data-placeholder', viewP );
3123+
3124+
viewRoot._appendChild( parse( '<container:p>1</container:p><container:p>2</container:p>' ) );
3125+
3126+
renderer.markToSync( 'children', viewRoot );
3127+
renderer.render();
3128+
3129+
expect( domRoot.innerHTML ).to.equal( '<p>1</p><p>2</p>' );
3130+
} );
31033131
} );
31043132
} );
31053133

0 commit comments

Comments
 (0)