Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

[IME][Safari] Fix IME composistion broken Issue in empty paragraph in Safari #217

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion src/utils/injecttypingmutationshandling.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,36 @@ class MutationHandler {
const modelPos = this.editing.mapper.toModelPosition( viewPos );
const insertedText = change.values[ 0 ].data;

// When we use Chinese IME in Safari, the dom selection won't be collapsed while composing.
// But the input command would still set a collapsed selection after insertion,
// make _domSelectionNeedsUpdate to be true and unnecessarily update the composition selection,
// which would break the IME composistion and causing the bug described in:
//
// https://github.com/ckeditor/ckeditor5/issues/1333
//
// This fix ensure the input command respects the actual dom selection while composing
// in whichever browser.
let resultRange;
const { document, domConverter } = this.editing.view;
if ( document.isComposing ) {
const domRoot = domConverter.mapViewToDom( document.selection.editableElement );
const domSelection = domRoot.ownerDocument.getSelection();

if ( !domSelection.isCollapsed && domSelection.anchorNode === domSelection.focusNode ) {
resultRange = this.editor.model.createRange(
modelPos, modelPos.getShiftedBy( domSelection.focusOffset - domSelection.anchorOffset )
);
}
}

this.editor.execute( 'input', {
// Replace   inserted by the browser with normal space.
// See comment in `_handleTextMutation`.
// In this case we don't need to do this before `diff` because we diff whole nodes.
// Just change   in case there are some.
text: insertedText.replace( /\u00A0/g, ' ' ),
range: this.editor.model.createRange( modelPos )
range: this.editor.model.createRange( modelPos ),
resultRange
} );
}
}
Expand Down
75 changes: 75 additions & 0 deletions tests/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,81 @@ describe( 'Input feature', () => {
expect( getModelData( model ) ).to.equal(
'<paragraph><$text bold="true">fo[]</$text><$text italic="true">ar</$text></paragraph>' );
} );

it( 'should not break composition in an empty paragraph in Safari', () => {
setModelData( model, '<paragraph>[]</paragraph>' );

// When we use Chinese IME in Safari, the dom selection won't be collapsed while composing
const p = viewRoot.getChild( 0 );
const domP = editor.editing.view.domConverter.mapViewToDom( p );
const getSelectionStub = testUtils.sinon.stub( document, 'getSelection' ).returns( {
rangeCount: 1,
isCollapsed: false,
anchorNode: domP,
anchorOffset: 0,
focusNode: domP,
focusOffset: 1,
getRangeAt: () => ( {
collapsed: false,
startContainer: domP,
startOffset: 0,
endContainer: domP,
endOffset: 1,
commonAncestorContainer: domP,
} ),
} );

viewDocument.fire( 'compositionstart' );
viewDocument.fire( 'mutations', [
{
type: 'children',
oldChildren: [],
newChildren: [ new ViewText( 'c' ) ],
node: viewRoot.getChild( 0 )
}
] );

expect( getSelectionStub.called ).to.equal( true );
expect( getModelData( model ) ).to.equal( '<paragraph>[c]</paragraph>' );
getSelectionStub.restore();
} );

it( 'should not break composition in an empty paragraph in browsers except Safari', () => {
setModelData( model, '<paragraph>[]</paragraph>' );

const p = viewRoot.getChild( 0 );
const domP = editor.editing.view.domConverter.mapViewToDom( p );
const getSelectionStub = testUtils.sinon.stub( document, 'getSelection' ).returns( {
rangeCount: 1,
isCollapsed: true,
anchorNode: domP,
anchorOffset: 1,
focusNode: domP,
focusOffset: 1,
getRangeAt: () => ( {
collapsed: true,
startContainer: domP,
startOffset: 1,
endContainer: domP,
endOffset: 1,
commonAncestorContainer: domP,
} ),
} );

viewDocument.fire( 'compositionstart' );
viewDocument.fire( 'mutations', [
{
type: 'children',
oldChildren: [],
newChildren: [ new ViewText( 'c' ) ],
node: viewRoot.getChild( 0 )
}
] );

expect( getSelectionStub.called ).to.equal( true );
expect( getModelData( model ) ).to.equal( '<paragraph>c[]</paragraph>' );
getSelectionStub.restore();
} );
} );
} );
} );
Expand Down