Skip to content

Commit

Permalink
Merge pull request #14418 from ckeditor/ck/14411
Browse files Browse the repository at this point in the history
Fix (engine): The editor should not crash while pressing backspace in an empty editor (in Firefox). Closes #14411. Closes #14050.
  • Loading branch information
arkflpc committed Jun 20, 2023
2 parents eff5cca + 0ba3737 commit 402e866
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
15 changes: 13 additions & 2 deletions packages/ckeditor5-engine/src/view/observer/inputobserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,19 @@ export default class InputObserver extends DomEventObserver<'beforeinput'> {
// @if CK_DEBUG_TYPING // }
} else if ( domTargetRanges.length ) {
targetRanges = domTargetRanges.map( domRange => {
return view.domConverter.domRangeToView( domRange )!;
} );
// Sometimes browser provides range that starts before editable node.
// We try to fall back to collapsed range at the valid end position.
// See https://github.com/ckeditor/ckeditor5/issues/14411.
// See https://github.com/ckeditor/ckeditor5/issues/14050.
const viewStart = view.domConverter.domPositionToView( domRange.startContainer, domRange.startOffset );
const viewEnd = view.domConverter.domPositionToView( domRange.endContainer, domRange.endOffset );

if ( viewStart ) {
return view.createRange( viewStart, viewEnd );
} else if ( viewEnd ) {
return view.createRange( viewEnd );
}
} ).filter( ( range ): range is ViewRange => !!range );

// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
// @if CK_DEBUG_TYPING // console.info( '%c[InputObserver]%c using target ranges:',
Expand Down
24 changes: 24 additions & 0 deletions packages/ckeditor5-engine/tests/view/observer/inputobserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,30 @@ describe( 'InputObserver', () => {
expect( viewRange2.end.offset ).to.equal( 2 );
} );

it( 'should provide fixed editing view ranges corresponding to DOM ranges passed along with the DOM event', () => {
const domRange = global.document.createRange();

// [<div contenteditable="true">
// <p>fo]o</p>
domRange.setStartBefore( domEditable );
domRange.setEnd( domEditable.firstChild.firstChild, 2 );

fireMockNativeBeforeInput( {
getTargetRanges: () => [ domRange ]
} );

expect( evtData.targetRanges ).to.have.length( 1 );

const viewRange = evtData.targetRanges[ 0 ];

expect( viewRange ).to.be.instanceOf( Range );

expect( viewRange.start.parent ).to.equal( viewRoot.getChild( 0 ).getChild( 0 ) );
expect( viewRange.start.offset ).to.equal( 2 );
expect( viewRange.end.parent ).to.equal( viewRoot.getChild( 0 ).getChild( 0 ) );
expect( viewRange.end.offset ).to.equal( 2 );
} );

it( 'should provide a range encompassing the selected object when selection is fake', () => {
const domRange = global.document.createRange();

Expand Down

0 comments on commit 402e866

Please sign in to comment.