Kaynağa Gözat

Merge pull request #122 from ckeditor/t/117

Fix: Fixed an error where using spellchecker on a word with a style applied sometimes resulted in that word being removed. Closes #117.
Piotrek Koszuliński 8 yıl önce
ebeveyn
işleme
0acaa208e9

+ 8 - 7
packages/ckeditor5-typing/src/input.js

@@ -408,9 +408,10 @@ function getMutationsContainer( mutations ) {
 		.find( element => element.is( 'containerElement' ) || element.is( 'rootElement' ) );
 }
 
-// Returns true if container children have mutated and more than a single text node was changed. Single text node
-// child insertion is handled in {@link module:typing/input~MutationHandler#_handleTextNodeInsertion} and text
-// mutation is handled in {@link module:typing/input~MutationHandler#_handleTextMutation}.
+// Returns true if container children have mutated or more than a single text node was changed.
+//
+// Single text node child insertion is handled in {@link module:typing/input~MutationHandler#_handleTextNodeInsertion}
+// while text mutation is handled in {@link module:typing/input~MutationHandler#_handleTextMutation}.
 //
 // @private
 // @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|
@@ -421,14 +422,14 @@ function containerChildrenMutated( mutations ) {
 		return false;
 	}
 
-	// Check if all mutations are `children` type, and there is no single text node mutation.
+	// Check if there is any mutation of `children` type or any mutation that changes more than one text node.
 	for ( const mutation of mutations ) {
-		if ( mutation.type !== 'children' || getSingleTextNodeChange( mutation ) ) {
-			return false;
+		if ( mutation.type === 'children' && !getSingleTextNodeChange( mutation ) ) {
+			return true;
 		}
 	}
 
-	return true;
+	return false;
 }
 
 // Returns true if provided array contains only {@link module:engine/model/text~Text model text nodes}.

+ 75 - 1
packages/ckeditor5-typing/tests/input.js

@@ -41,7 +41,7 @@ describe( 'Input feature', () => {
 
 		return VirtualTestEditor
 			.create( {
-				plugins: [ Input, Paragraph ]
+				plugins: [ Input, Paragraph, Bold ]
 			} )
 			.then( newEditor => {
 				// Mock image feature.
@@ -126,6 +126,50 @@ describe( 'Input feature', () => {
 			expect( getViewData( view ) ).to.equal( '<p>x{}</p>' );
 		} );
 
+		it( 'should handle multiple text mutations', () => {
+			editor.setData( '<p>foo<strong>bar</strong></p>' );
+
+			view.fire( 'mutations', [
+				{
+					type: 'text',
+					oldText: 'foo',
+					newText: 'foob',
+					node: viewRoot.getChild( 0 ).getChild( 0 )
+				},
+				{
+					type: 'text',
+					oldText: 'bar',
+					newText: 'ar',
+					node: viewRoot.getChild( 0 ).getChild( 1 ).getChild( 0 )
+				}
+			] );
+
+			expect( getModelData( model ) ).to.equal( '<paragraph>foob[]<$text bold="true">ar</$text></paragraph>' );
+			expect( getViewData( view ) ).to.equal( '<p>foob{}<strong>ar</strong></p>' );
+		} );
+
+		it( 'should handle multiple text node insertion', () => {
+			editor.setData( '<p></p><p></p>' );
+
+			view.fire( 'mutations', [
+				{
+					type: 'children',
+					oldChildren: [],
+					newChildren: [ new ViewText( 'x' ) ],
+					node: viewRoot.getChild( 0 )
+				},
+				{
+					type: 'children',
+					oldChildren: [],
+					newChildren: [ new ViewText( 'y' ) ],
+					node: viewRoot.getChild( 1 )
+				}
+			] );
+
+			expect( getModelData( model ) ).to.equal( '<paragraph>x</paragraph><paragraph>y[]</paragraph>' );
+			expect( getViewData( view ) ).to.equal( '<p>x</p><p>y{}</p>' );
+		} );
+
 		it( 'should do nothing when two nodes were inserted', () => {
 			editor.setData( '<p></p>' );
 
@@ -947,6 +991,36 @@ describe( 'Input feature', () => {
 			expect( getModelData( model ) ).to.equal( '<paragraph><$text bold="true">[]textx</$text></paragraph>' );
 			expect( getViewData( view ) ).to.equal( '<p><strong>{}textx</strong></p>' );
 		} );
+
+		// #117.
+		it( 'should handle mixed mutations', () => {
+			setModelData( model, '<paragraph><$text bold="true">Foo bar aple</$text></paragraph>' );
+
+			const paragraph = viewRoot.getChild( 0 );
+			const strong = paragraph.getChild( 0 );
+			const viewSelection = new ViewSelection();
+			viewSelection.setCollapsedAt( paragraph, 0 );
+
+			// Simulate mutations and DOM change.
+			domRoot.childNodes[ 0 ].innerHTML = '<strong>Foo bar </strong><b>apple</b>';
+			view.fire( 'mutations', [
+				{
+					type: 'text',
+					oldText: 'Foo bar aple',
+					newText: 'Foo bar ',
+					node: viewRoot.getChild( 0 ).getChild( 0 )
+				},
+				{
+					type: 'children',
+					oldChildren: [ strong ],
+					newChildren: [ strong, new ViewElement( 'b', null, new ViewText( 'apple' ) ) ],
+					node: paragraph
+				}
+			], viewSelection );
+
+			expect( getModelData( model ) ).to.equal( '<paragraph><$text bold="true">[]Foo bar apple</$text></paragraph>' );
+			expect( getViewData( view ) ).to.equal( '<p><strong>{}Foo bar apple</strong></p>' );
+		} );
 	} );
 } );