8
0
Pārlūkot izejas kodu

Try to recognize if mutation was generated by typing.

Krzysztof Krztoń 8 gadi atpakaļ
vecāks
revīzija
4500fde013
1 mainītis faili ar 60 papildinājumiem un 10 dzēšanām
  1. 60 10
      packages/ckeditor5-typing/src/input.js

+ 60 - 10
packages/ckeditor5-typing/src/input.js

@@ -146,12 +146,26 @@ class MutationHandler {
 	 */
 	handle( mutations, viewSelection ) {
 		for ( let mutation of mutations ) {
+			// console.log( 'if', mutation );
 			// Fortunately it will never be both.
 			this._handleTextMutation( mutation, viewSelection );
 			this._handleTextNodeInsertion( mutation );
 		}
 	}
 
+	// TODO needs proper description
+	// Check if mutation is normal typing.
+	// There is also composition (mutations will be blocked during composing in future) and spellchecking.
+	// There are also cases when spell checking generates one insertion and no deletions (like hous -> house)
+	// and the mutation is identical as typing.
+	_isTyping( insertions, deletions, firstChangeAt, lastChangeAt, viewSelection ) {
+		const viewSelectionAnchorOffset = viewSelection ? viewSelection.anchor.offset : null;
+
+		return deletions === 0 && insertions == 1 &&
+			firstChangeAt && lastChangeAt && ( lastChangeAt - firstChangeAt === 0 ) &&
+			( viewSelectionAnchorOffset <= firstChangeAt + 1 );
+	}
+
 	_handleTextMutation( mutation, viewSelection ) {
 		if ( mutation.type != 'text' ) {
 			return;
@@ -204,23 +218,59 @@ class MutationHandler {
 			}
 		}
 
-		// Try setting new model selection according to passed view selection.
-		let modelSelectionPosition = null;
+		// TODO transform into human readable and understandable text.
+		// For insertions of the same character in a row, like
+		// ab^cde - inserting c
+		// and
+		// abc^de - inserting c
+		// the diff is the same.
+		// This causes the problem with using ModelRange.createFromPositionAndShift( modelPos, 0 ); (passing when there is no removeRange)
+		// because the last character in the sequence of the same characters is always recognized as an insertion.
+		// From the other hand without ModelRange.createFromPositionAndShift( modelPos, 0 ); it works fine, but spellchecking
+		// cases which cannot be differentiated from typing ( hous -> house ) is broken because `InputCommand` wll use
+		// default selection which is [hous] to do text replacement (results in e[]).
+
+		// Get the position in view and model where the changes will happen.
+		let viewPos = new ViewPosition( mutation.node, firstChangeAt );
 
-		if ( viewSelection ) {
-			modelSelectionPosition = this.editing.mapper.toModelPosition( viewSelection.anchor );
+		// TODO references to previous comment about diff with same character sequence. Needs proper, dteailed description.
+		if ( viewSelection && viewSelection.anchor.offset <= firstChangeAt ) {
+			viewPos = new ViewPosition( mutation.node, viewSelection.anchor.offset - 1 );
 		}
 
-		// Get the position in view and model where the changes will happen.
-		const viewPos = new ViewPosition( mutation.node, firstChangeAt );
-		const modelPos = this.editing.mapper.toModelPosition( viewPos );
-		const removeRange = deletions > 0 ? ModelRange.createFromPositionAndShift( modelPos, deletions ) : null;
-		const insertText = newText.substr( firstChangeAt, insertions );
+		let modelPos = this.editing.mapper.toModelPosition( viewPos );
+		let removeRange = ModelRange.createFromPositionAndShift( modelPos, deletions || 0 );
+		let insertText = newText.substr( firstChangeAt, insertions );
+
+		// TODO detailed description what is going on here.
+		if ( viewSelection && !this._isTyping( insertions, deletions, firstChangeAt, lastChangeAt, viewSelection ) ) {
+			// The beginning of the corrected word is always at the fixed position no matter what was changed
+			// by spellchecking mechanism so it may be recognized by getting last space before corrected word.
+			let lastSpaceBeforeChangeAt = 0;
+
+			for ( let i = 0; i < newText.length; i++ ) {
+				if ( newText[ i ] === ' ' ) {
+					if ( i < firstChangeAt ) {
+						lastSpaceBeforeChangeAt = i + 1;
+					} else {
+						break;
+					}
+				}
+			}
+
+			let correctedText = newText.substring( lastSpaceBeforeChangeAt, viewSelection.anchor.offset );
+
+			if ( correctedText.length ) {
+				insertText = correctedText;
+				viewPos = new ViewPosition( mutation.node, lastSpaceBeforeChangeAt );
+				modelPos = this.editing.mapper.toModelPosition( viewPos );
+				removeRange = ModelRange.createFromPositionAndShift( modelPos, insertText.length - insertions + deletions );
+			}
+		}
 
 		this.editor.execute( 'input', {
 			text: insertText,
 			range: removeRange,
-			selectionAnchor: modelSelectionPosition,
 			buffer: this.buffer
 		} );
 	}