Skip to content

Commit

Permalink
Merge pull request #13685 from ckeditor/ck/13583
Browse files Browse the repository at this point in the history
Fix (typing): Text suggestions should replace the whole words. Closes #13583.

Other (engine): The `targetRanges` property of the `beforeInput` event data should be fixed to not cross limit elements' boundaries. See #13583.
  • Loading branch information
arkflpc authored Apr 11, 2023
2 parents 444c549 + ef2b573 commit c6a8e85
Show file tree
Hide file tree
Showing 7 changed files with 622 additions and 136 deletions.
37 changes: 36 additions & 1 deletion packages/ckeditor5-engine/src/controller/editingcontroller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
* @module engine/controller/editingcontroller
*/

import { CKEditorError, ObservableMixin } from '@ckeditor/ckeditor5-utils';
import {
CKEditorError,
ObservableMixin,
type GetCallback
} from '@ckeditor/ckeditor5-utils';

import RootEditableElement from '../view/rooteditableelement';
import View from '../view/view';
Expand All @@ -28,14 +32,18 @@ import {

import { convertSelectionChange } from '../conversion/upcasthelpers';

import { tryFixingRange } from '../model/utils/selection-post-fixer';

import type { default as Model, AfterChangesEvent, BeforeChangesEvent } from '../model/model';
import type ModelItem from '../model/item';
import type ModelText from '../model/text';
import type ModelTextProxy from '../model/textproxy';
import type Schema from '../model/schema';
import type { DocumentChangeEvent } from '../model/document';
import type { Marker } from '../model/markercollection';
import type { StylesProcessor } from '../view/stylesmap';
import type { ViewDocumentSelectionChangeEvent } from '../view/observer/selectionobserver';
import type { ViewDocumentInputEvent } from '../view/observer/inputobserver';

// @if CK_DEBUG_ENGINE // const { dumpTrees, initDocumentDumping } = require( '../dev-utils/utils' );

Expand Down Expand Up @@ -115,6 +123,12 @@ export default class EditingController extends ObservableMixin() {
convertSelectionChange( this.model, this.mapper )
);

// Fix `beforeinput` target ranges so that they map to the valid model ranges.
this.listenTo<ViewDocumentInputEvent>( this.view.document, 'beforeinput',
fixTargetRanges( this.mapper, this.model.schema ),
{ priority: 'high' }
);

// Attach default model converters.
this.downcastDispatcher.on<DowncastInsertEvent<ModelText | ModelTextProxy>>( 'insert:$text', insertText(), { priority: 'lowest' } );
this.downcastDispatcher.on<DowncastInsertEvent>( 'insert', insertAttributesAndChildren(), { priority: 'lowest' } );
Expand Down Expand Up @@ -232,3 +246,24 @@ export default class EditingController extends ObservableMixin() {
} );
}
}

/**
* Checks whether the target ranges provided by the `beforeInput` event can be properly mapped to model ranges and fixes them if needed.
*
* This is using the same logic as the selection post-fixer.
*/
function fixTargetRanges( mapper: Mapper, schema: Schema ): GetCallback<ViewDocumentInputEvent> {
return ( evt, data ) => {
for ( let i = 0; i < data.targetRanges.length; i++ ) {
const viewRange = data.targetRanges[ i ];
const modelRange = mapper.toModelRange( viewRange );
const correctedRange = tryFixingRange( modelRange, schema );

if ( !correctedRange || correctedRange.isEqual( modelRange ) ) {
continue;
}

data.targetRanges[ i ] = mapper.toViewRange( correctedRange );
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,11 @@ function selectionPostFixer( writer: Writer, model: Model ): boolean {
/**
* Tries fixing a range if it's incorrect.
*
* **Note:** This helper is used by the selection post-fixer and to fix the `beforeinput` target ranges.
*
* @returns Returns fixed range or null if range is valid.
*/
function tryFixingRange( range: Range, schema: Schema ) {
export function tryFixingRange( range: Range, schema: Schema ): Range | null {
if ( range.isCollapsed ) {
return tryFixingCollapsedRange( range, schema );
}
Expand Down
3 changes: 2 additions & 1 deletion packages/ckeditor5-engine/src/view/domconverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,8 @@ export default class DomConverter {
} else {
const domBefore = domParent.childNodes[ domOffset - 1 ];

if ( isText( domBefore ) && isInlineFiller( domBefore ) ) {
// Jump over an inline filler (and also on Firefox jump over a block filler while pressing backspace in an empty paragraph).
if ( isText( domBefore ) && isInlineFiller( domBefore ) || this.isBlockFiller( domBefore ) ) {
return this.domPositionToView( domBefore.parentNode!, indexOf( domBefore ) );
}

Expand Down
Loading

0 comments on commit c6a8e85

Please sign in to comment.