@@ -79,6 +79,14 @@ const alphabetsContainingSpaces = new RegExp(
7979 ')$' ,
8080) ;
8181
82+ /**
83+ * Spell-checking on mobile devices does not stop at inline tags like b, i, u
84+ * but it hits a barrier on different nodes like div for example. The code
85+ * below constructs a crude selector to match if the node is such a barrier.
86+ */
87+ const spellCheckingIgnoredTags = [ 'a' , 'b' , 'i' , 'u' , 'span' , 'font' , 'superscript' , 'subscript' ] ;
88+ const spellCheckingBarrier = spellCheckingIgnoredTags . map ( t => `:not(${ t } )` ) . join ( '' ) ;
89+
8290/**
8391 * These javascript event types might, in case of safari or spell-checking
8492 * keyboard, trigger dom events in multiple javascript stacks. They will require
@@ -941,8 +949,11 @@ export class EventNormalizer {
941949 | DeleteWordAction
942950 | DeleteHardLineAction
943951 | DeleteContentAction {
944- const isInsertOrRemoveAction = hasMutatedElements && ! inputTypeCommands . has ( inputType ) ;
945- if ( isInsertOrRemoveAction ) {
952+ const isMutationAction = hasMutatedElements && ! inputTypeCommands . has ( inputType ) ;
953+ // These two particular keys might have been defaultPrevented to avoid
954+ // flickering and thus trigger no mutation but still need to be handled.
955+ const isRemoveAction = key === 'Backspace' || key === 'Delete' ;
956+ if ( isMutationAction || isRemoveAction ) {
946957 if ( key === 'Backspace' || key === 'Delete' ) {
947958 return this . _getRemoveAction ( key , inputType ) ;
948959 } else if ( key === 'Enter' ) {
@@ -1599,6 +1610,26 @@ export class EventNormalizer {
15991610 const selection = this . _getSelection ( ) ;
16001611 const [ offsetNode , offset ] = targetDeepest ( selection . anchorNode , selection . anchorOffset ) ;
16011612 this . _initialCaretPosition = { offsetNode, offset } ;
1613+
1614+ // Backspace cannot always be prevented as preventing a backspace in a
1615+ // text node would throw off spell-checking on mobile for example.
1616+ if ( ev . key === 'Backspace' ) {
1617+ const forward = selection . direction === Direction . FORWARD ;
1618+ const start = forward ? selection . anchorNode : selection . focusNode ;
1619+ const startOffset = forward ? selection . anchorOffset : selection . focusOffset ;
1620+ if (
1621+ ( startOffset === 0 && ! start . previousSibling ) ||
1622+ selection . anchorNode . parentElement . closest ( spellCheckingBarrier ) !==
1623+ selection . focusNode . parentElement . closest ( spellCheckingBarrier )
1624+ ) {
1625+ // Allowed cases for preventing is:
1626+ // 1. At the start of the node
1627+ // 2. When the anchor and focus of the selection are set in
1628+ // nodes that are separated of each other by a node that is
1629+ // considered to be a barrier for spell-checking purposes.
1630+ ev . preventDefault ( ) ;
1631+ }
1632+ }
16021633 }
16031634 /**
16041635 * Set internal properties of the pointer down event to retrieve them later
0 commit comments