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

Commit 3583cae

Browse files
author
Piotr Jasiun
authored
Merge pull request #883 from ckeditor/t/882
Fix: Mutations inserting bogus BR on the end of the block element are filtered out by mutation observer. Closes #882.
2 parents e08b019 + 3ca9299 commit 3583cae

File tree

2 files changed

+122
-1
lines changed

2 files changed

+122
-1
lines changed

src/view/observer/mutationobserver.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export default class MutationObserver extends Observer {
149149
if ( mutation.type === 'childList' ) {
150150
const element = domConverter.getCorrespondingViewElement( mutation.target );
151151

152-
if ( element ) {
152+
if ( element && !this._isBogusBrMutation( mutation ) ) {
153153
mutatedElements.add( element );
154154
}
155155
}
@@ -233,6 +233,28 @@ export default class MutationObserver extends Observer {
233233
// view (which has not been changed). In order to "reset DOM" we render the view again.
234234
this.document.render();
235235
}
236+
237+
/**
238+
* Checks if mutation was generated by the browser inserting bogus br on the end of the block element.
239+
* Such mutations are generated while pressing space or performing native spellchecker correction
240+
* on the end of the block element in Firefox browser.
241+
*
242+
* @private
243+
* @param {Object} mutation Native mutation object.
244+
* @returns {Boolean}
245+
*/
246+
_isBogusBrMutation( mutation ) {
247+
let addedNode = null;
248+
249+
// Check if mutation added only one node on the end of its parent.
250+
if ( mutation.nextSibling === null && mutation.removedNodes.length === 0 && mutation.addedNodes.length == 1 ) {
251+
addedNode = this.domConverter.domToView( mutation.addedNodes[ 0 ], {
252+
withChildren: false
253+
} );
254+
}
255+
256+
return addedNode && addedNode.is( 'element', 'br' );
257+
}
236258
}
237259

238260
/**

tests/view/observer/mutationobserver.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,105 @@ describe( 'MutationObserver', () => {
245245
expect( lastMutations[ 0 ].oldChildren.length ).to.equal( 0 );
246246
} );
247247

248+
it( 'should ignore mutation with bogus br inserted on the end of the empty paragraph', () => {
249+
viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
250+
251+
viewDocument.render();
252+
253+
const domP = domEditor.childNodes[ 2 ];
254+
domP.appendChild( document.createElement( 'br' ) );
255+
256+
mutationObserver.flush();
257+
258+
expect( lastMutations.length ).to.equal( 0 );
259+
} );
260+
261+
it( 'should ignore mutation with bogus br inserted on the end of the paragraph with text', () => {
262+
viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
263+
264+
viewDocument.render();
265+
266+
const domP = domEditor.childNodes[ 2 ];
267+
domP.appendChild( document.createElement( 'br' ) );
268+
269+
mutationObserver.flush();
270+
271+
expect( lastMutations.length ).to.equal( 0 );
272+
} );
273+
274+
it( 'should ignore mutation with bogus br inserted on the end of the paragraph while processing text mutations', () => {
275+
viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
276+
277+
viewDocument.render();
278+
279+
const domP = domEditor.childNodes[ 2 ];
280+
domP.childNodes[ 0 ].data = 'foo ';
281+
domP.appendChild( document.createElement( 'br' ) );
282+
283+
mutationObserver.flush();
284+
285+
expect( lastMutations.length ).to.equal( 1 );
286+
287+
expect( lastMutations[ 0 ].oldText ).to.equal( 'foo' );
288+
expect( lastMutations[ 0 ].newText ).to.equal( 'foo ' );
289+
} );
290+
291+
it( 'should not ignore mutation with br inserted not on the end of the paragraph', () => {
292+
viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
293+
294+
viewDocument.render();
295+
296+
const domP = domEditor.childNodes[ 2 ];
297+
domP.insertBefore( document.createElement( 'br' ), domP.childNodes[ 0 ] );
298+
299+
mutationObserver.flush();
300+
301+
expect( lastMutations.length ).to.equal( 1 );
302+
303+
expect( lastMutations[ 0 ].newChildren.length ).to.equal( 2 );
304+
expect( lastMutations[ 0 ].newChildren[ 0 ].name ).to.equal( 'br' );
305+
expect( lastMutations[ 0 ].newChildren[ 1 ].data ).to.equal( 'foo' );
306+
307+
expect( lastMutations[ 0 ].oldChildren.length ).to.equal( 1 );
308+
} );
309+
310+
it( 'should not ignore mutation inserting element different than br on the end of the empty paragraph', () => {
311+
viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
312+
313+
viewDocument.render();
314+
315+
const domP = domEditor.childNodes[ 2 ];
316+
domP.appendChild( document.createElement( 'span' ) );
317+
318+
mutationObserver.flush();
319+
320+
expect( lastMutations.length ).to.equal( 1 );
321+
322+
expect( lastMutations[ 0 ].newChildren.length ).to.equal( 1 );
323+
expect( lastMutations[ 0 ].newChildren[ 0 ].name ).to.equal( 'span' );
324+
325+
expect( lastMutations[ 0 ].oldChildren.length ).to.equal( 0 );
326+
} );
327+
328+
it( 'should not ignore mutation inserting element different than br on the end of the paragraph with text', () => {
329+
viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
330+
331+
viewDocument.render();
332+
333+
const domP = domEditor.childNodes[ 2 ];
334+
domP.appendChild( document.createElement( 'span' ) );
335+
336+
mutationObserver.flush();
337+
338+
expect( lastMutations.length ).to.equal( 1 );
339+
340+
expect( lastMutations[ 0 ].newChildren.length ).to.equal( 2 );
341+
expect( lastMutations[ 0 ].newChildren[ 0 ].data ).to.equal( 'foo' );
342+
expect( lastMutations[ 0 ].newChildren[ 1 ].name ).to.equal( 'span' );
343+
344+
expect( lastMutations[ 0 ].oldChildren.length ).to.equal( 1 );
345+
} );
346+
248347
function expectDomEditorNotToChange() {
249348
expect( domEditor.childNodes.length ).to.equal( 2 );
250349
expect( domEditor.childNodes[ 0 ].tagName ).to.equal( 'P' );

0 commit comments

Comments
 (0)