Kaynağa Gözat

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.
Piotr Jasiun 8 yıl önce
ebeveyn
işleme
9ba3d9d5d5

+ 23 - 1
packages/ckeditor5-engine/src/view/observer/mutationobserver.js

@@ -149,7 +149,7 @@ export default class MutationObserver extends Observer {
 			if ( mutation.type === 'childList' ) {
 				const element = domConverter.getCorrespondingViewElement( mutation.target );
 
-				if ( element ) {
+				if ( element && !this._isBogusBrMutation( mutation ) ) {
 					mutatedElements.add( element );
 				}
 			}
@@ -233,6 +233,28 @@ export default class MutationObserver extends Observer {
 		// view (which has not been changed). In order to "reset DOM" we render the view again.
 		this.document.render();
 	}
+
+	/**
+	 * Checks if mutation was generated by the browser inserting bogus br on the end of the block element.
+	 * Such mutations are generated while pressing space or performing native spellchecker correction
+	 * on the end of the block element in Firefox browser.
+	 *
+	 * @private
+	 * @param {Object} mutation Native mutation object.
+	 * @returns {Boolean}
+	 */
+	_isBogusBrMutation( mutation ) {
+		let addedNode = null;
+
+		// Check if mutation added only one node on the end of its parent.
+		if ( mutation.nextSibling === null && mutation.removedNodes.length === 0 && mutation.addedNodes.length == 1 ) {
+			addedNode = this.domConverter.domToView( mutation.addedNodes[ 0 ], {
+				withChildren: false
+			} );
+		}
+
+		return addedNode && addedNode.is( 'element', 'br' );
+	}
 }
 
 /**

+ 99 - 0
packages/ckeditor5-engine/tests/view/observer/mutationobserver.js

@@ -245,6 +245,105 @@ describe( 'MutationObserver', () => {
 		expect( lastMutations[ 0 ].oldChildren.length ).to.equal( 0 );
 	} );
 
+	it( 'should ignore mutation with bogus br inserted on the end of the empty paragraph', () => {
+		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
+
+		viewDocument.render();
+
+		const domP = domEditor.childNodes[ 2 ];
+		domP.appendChild( document.createElement( 'br' ) );
+
+		mutationObserver.flush();
+
+		expect( lastMutations.length ).to.equal( 0 );
+	} );
+
+	it( 'should ignore mutation with bogus br inserted on the end of the paragraph with text', () => {
+		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
+
+		viewDocument.render();
+
+		const domP = domEditor.childNodes[ 2 ];
+		domP.appendChild( document.createElement( 'br' ) );
+
+		mutationObserver.flush();
+
+		expect( lastMutations.length ).to.equal( 0 );
+	} );
+
+	it( 'should ignore mutation with bogus br inserted on the end of the paragraph while processing text mutations', () => {
+		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
+
+		viewDocument.render();
+
+		const domP = domEditor.childNodes[ 2 ];
+		domP.childNodes[ 0 ].data = 'foo ';
+		domP.appendChild( document.createElement( 'br' ) );
+
+		mutationObserver.flush();
+
+		expect( lastMutations.length ).to.equal( 1 );
+
+		expect( lastMutations[ 0 ].oldText ).to.equal( 'foo' );
+		expect( lastMutations[ 0 ].newText ).to.equal( 'foo ' );
+	} );
+
+	it( 'should not ignore mutation with br inserted not on the end of the paragraph', () => {
+		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
+
+		viewDocument.render();
+
+		const domP = domEditor.childNodes[ 2 ];
+		domP.insertBefore( document.createElement( 'br' ), domP.childNodes[ 0 ] );
+
+		mutationObserver.flush();
+
+		expect( lastMutations.length ).to.equal( 1 );
+
+		expect( lastMutations[ 0 ].newChildren.length ).to.equal( 2 );
+		expect( lastMutations[ 0 ].newChildren[ 0 ].name ).to.equal( 'br' );
+		expect( lastMutations[ 0 ].newChildren[ 1 ].data ).to.equal( 'foo' );
+
+		expect( lastMutations[ 0 ].oldChildren.length ).to.equal( 1 );
+	} );
+
+	it( 'should not ignore mutation inserting element different than br on the end of the empty paragraph', () => {
+		viewRoot.appendChildren( parse( '<container:p></container:p>' ) );
+
+		viewDocument.render();
+
+		const domP = domEditor.childNodes[ 2 ];
+		domP.appendChild( document.createElement( 'span' ) );
+
+		mutationObserver.flush();
+
+		expect( lastMutations.length ).to.equal( 1 );
+
+		expect( lastMutations[ 0 ].newChildren.length ).to.equal( 1 );
+		expect( lastMutations[ 0 ].newChildren[ 0 ].name ).to.equal( 'span' );
+
+		expect( lastMutations[ 0 ].oldChildren.length ).to.equal( 0 );
+	} );
+
+	it( 'should not ignore mutation inserting element different than br on the end of the paragraph with text', () => {
+		viewRoot.appendChildren( parse( '<container:p>foo</container:p>' ) );
+
+		viewDocument.render();
+
+		const domP = domEditor.childNodes[ 2 ];
+		domP.appendChild( document.createElement( 'span' ) );
+
+		mutationObserver.flush();
+
+		expect( lastMutations.length ).to.equal( 1 );
+
+		expect( lastMutations[ 0 ].newChildren.length ).to.equal( 2 );
+		expect( lastMutations[ 0 ].newChildren[ 0 ].data ).to.equal( 'foo' );
+		expect( lastMutations[ 0 ].newChildren[ 1 ].name ).to.equal( 'span' );
+
+		expect( lastMutations[ 0 ].oldChildren.length ).to.equal( 1 );
+	} );
+
 	function expectDomEditorNotToChange() {
 		expect( domEditor.childNodes.length ).to.equal( 2 );
 		expect( domEditor.childNodes[ 0 ].tagName ).to.equal( 'P' );