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

Commit b7e2bfe

Browse files
authored
Merge pull request #1811 from ckeditor/i/5600
Fix: Changes irrelevant to the view (e.g. inside UIElements) will no longer force a view render nor will they trigger mutation event on the document. Closes ckeditor/ckeditor5#5600.
2 parents 28c6f90 + 6e2a5d3 commit b7e2bfe

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

src/view/observer/mutationobserver.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,14 @@ export default class MutationObserver extends Observer {
244244
}
245245
}
246246

247-
this.document.fire( 'mutations', viewMutations, viewSelection );
247+
// In case only non-relevant mutations were recorded it skips the event and force render (#5600).
248+
if ( viewMutations.length ) {
249+
this.document.fire( 'mutations', viewMutations, viewSelection );
248250

249-
// If nothing changes on `mutations` event, at this point we have "dirty DOM" (changed) and de-synched
250-
// view (which has not been changed). In order to "reset DOM" we render the view again.
251-
this.view.forceRender();
251+
// If nothing changes on `mutations` event, at this point we have "dirty DOM" (changed) and de-synched
252+
// view (which has not been changed). In order to "reset DOM" we render the view again.
253+
this.view.forceRender();
254+
}
252255

253256
function sameNodes( child1, child2 ) {
254257
// First level of comparison (array of children vs array of children) – use the Lodash's default behavior.

src/view/uielement.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ export default class UIElement extends Element {
123123
* return domElement;
124124
* };
125125
*
126+
* If changes in your UI element should trigger some editor UI update you should call
127+
* the {@link module:core/editor/editorui~EditorUI#update `editor.ui.update()`} method
128+
* after rendering your UI element.
129+
*
126130
* @param {Document} domDocument
127131
* @returns {HTMLElement}
128132
*/

tests/view/observer/mutationobserver.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ describe( 'MutationObserver', () => {
404404

405405
mutationObserver.flush();
406406

407-
expect( lastMutations.length ).to.equal( 0 );
407+
expect( lastMutations ).to.be.null;
408408
} );
409409

410410
it( 'should ignore mutation with bogus br inserted on the end of the paragraph with text', () => {
@@ -417,7 +417,7 @@ describe( 'MutationObserver', () => {
417417

418418
mutationObserver.flush();
419419

420-
expect( lastMutations.length ).to.equal( 0 );
420+
expect( lastMutations ).to.be.null;
421421
} );
422422

423423
it( 'should ignore mutation with bogus br inserted on the end of the paragraph while processing text mutations', () => {
@@ -449,7 +449,7 @@ describe( 'MutationObserver', () => {
449449

450450
mutationObserver.flush();
451451

452-
expect( lastMutations.length ).to.equal( 0 );
452+
expect( lastMutations ).to.be.null;
453453
} );
454454

455455
// This case is more tricky than the previous one because DOMConverter will return a different
@@ -528,6 +528,7 @@ describe( 'MutationObserver', () => {
528528
} );
529529

530530
describe( 'UIElement integration', () => {
531+
const renderStub = sinon.stub();
531532
function createUIElement( name ) {
532533
const element = new UIElement( name );
533534

@@ -546,14 +547,24 @@ describe( 'MutationObserver', () => {
546547
viewRoot._appendChild( uiElement );
547548

548549
view.forceRender();
550+
renderStub.reset();
551+
view.on( 'render', renderStub );
549552
} );
550553

551554
it( 'should not collect text mutations from UIElement', () => {
552555
domEditor.childNodes[ 2 ].childNodes[ 0 ].data = 'foom';
553556

554557
mutationObserver.flush();
555558

556-
expect( lastMutations.length ).to.equal( 0 );
559+
expect( lastMutations ).to.be.null;
560+
} );
561+
562+
it( 'should not cause a render from UIElement', () => {
563+
domEditor.childNodes[ 2 ].childNodes[ 0 ].data = 'foom';
564+
565+
mutationObserver.flush();
566+
567+
expect( renderStub.callCount ).to.be.equal( 0 );
557568
} );
558569

559570
it( 'should not collect child mutations from UIElement', () => {
@@ -562,7 +573,16 @@ describe( 'MutationObserver', () => {
562573

563574
mutationObserver.flush();
564575

565-
expect( lastMutations.length ).to.equal( 0 );
576+
expect( lastMutations ).to.be.null;
577+
} );
578+
579+
it( 'should not cause a render when UIElement gets a child', () => {
580+
const span = document.createElement( 'span' );
581+
domEditor.childNodes[ 2 ].appendChild( span );
582+
583+
mutationObserver.flush();
584+
585+
expect( renderStub.callCount ).to.be.equal( 0 );
566586
} );
567587
} );
568588

0 commit comments

Comments
 (0)