@@ -98,7 +98,7 @@ function domBoundsAround(tile: Tile, from: number, to: number, offset: number):
9898
9999export function applyDOMChange ( view : EditorView , domChange : DOMChange ) : boolean {
100100 let change : undefined | { from : number , to : number , insert : Text }
101- let { newSel} = domChange , sel = view . state . selection . main
101+ let { newSel} = domChange , { state } = view , sel = state . selection . main
102102 let lastKey = view . inputState . lastKeyTime > Date . now ( ) - 100 ? view . inputState . lastKeyCode : - 1
103103 if ( domChange . bounds ) {
104104 let { from, to} = domChange . bounds
@@ -109,44 +109,36 @@ export function applyDOMChange(view: EditorView, domChange: DOMChange): boolean
109109 preferredPos = sel . to
110110 preferredSide = "end"
111111 }
112- let diff = findDiff ( view . state . doc . sliceString ( from , to , LineBreakPlaceholder ) , domChange . text ,
113- preferredPos - from , preferredSide )
114- if ( diff ) {
112+ let cmp = state . doc . sliceString ( from , to , LineBreakPlaceholder ) , selEnd , diff
113+ if ( ! sel . empty && sel . from >= from && sel . to <= to && ( domChange . typeOver || cmp != domChange . text ) &&
114+ cmp . slice ( 0 , sel . from - from ) == domChange . text . slice ( 0 , sel . from - from ) &&
115+ cmp . slice ( sel . to - from ) == domChange . text . slice ( selEnd = domChange . text . length - ( cmp . length - ( sel . to - from ) ) ) ) {
116+ // This looks like a selection replacement
117+ change = { from : sel . from , to : sel . to ,
118+ insert : Text . of ( domChange . text . slice ( sel . from - from , selEnd ) . split ( LineBreakPlaceholder ) ) }
119+ } else if ( diff = findDiff ( cmp , domChange . text , preferredPos - from , preferredSide ) ) {
115120 // Chrome inserts two newlines when pressing shift-enter at the
116121 // end of a line. DomChange drops one of those.
117122 if ( browser . chrome && lastKey == 13 &&
118- diff . toB == diff . from + 2 && domChange . text . slice ( diff . from , diff . toB ) == LineBreakPlaceholder + LineBreakPlaceholder )
123+ diff . toB == diff . from + 2 && domChange . text . slice ( diff . from , diff . toB ) == LineBreakPlaceholder + LineBreakPlaceholder )
119124 diff . toB --
120125
121126 change = { from : from + diff . from , to : from + diff . toA ,
122127 insert : Text . of ( domChange . text . slice ( diff . from , diff . toB ) . split ( LineBreakPlaceholder ) ) }
123128 }
124- } else if ( newSel && ( ! view . hasFocus && view . state . facet ( editable ) || sameSelPos ( newSel , sel ) ) ) {
129+ } else if ( newSel && ( ! view . hasFocus && state . facet ( editable ) || sameSelPos ( newSel , sel ) ) ) {
125130 newSel = null
126131 }
127132
128133 if ( ! change && ! newSel ) return false
129134
130- if ( ! change && domChange . typeOver && ! sel . empty && newSel && newSel . main . empty ) {
131- // Heuristic to notice typing over a selected character
132- change = { from : sel . from , to : sel . to , insert : view . state . doc . slice ( sel . from , sel . to ) }
133- } else if ( ( browser . mac || browser . android ) && change && change . from == change . to && change . from == sel . head - 1 &&
135+ if ( ( browser . mac || browser . android ) && change && change . from == change . to && change . from == sel . head - 1 &&
134136 / ^ \. ? $ / . test ( change . insert . toString ( ) ) && view . contentDOM . getAttribute ( "autocorrect" ) == "off" ) {
135137 // Detect insert-period-on-double-space Mac and Android behavior,
136138 // and transform it into a regular space insert.
137139 if ( newSel && change . insert . length == 2 ) newSel = EditorSelection . single ( newSel . main . anchor - 1 , newSel . main . head - 1 )
138140 change = { from : change . from , to : change . to , insert : Text . of ( [ change . insert . toString ( ) . replace ( "." , " " ) ] ) }
139- } else if ( change && change . from >= sel . from && change . to <= sel . to &&
140- ( change . from != sel . from || change . to != sel . to ) &&
141- ( sel . to - sel . from ) - ( change . to - change . from ) <= 4 ) {
142- // If the change is inside the selection and covers most of it,
143- // assume it is a selection replace (with identical characters at
144- // the start/end not included in the diff)
145- change = {
146- from : sel . from , to : sel . to ,
147- insert : view . state . doc . slice ( sel . from , change . from ) . append ( change . insert ) . append ( view . state . doc . slice ( change . to , sel . to ) )
148- }
149- } else if ( view . state . doc . lineAt ( sel . from ) . to < sel . to && view . docView . lineHasWidget ( sel . to ) &&
141+ } else if ( state . doc . lineAt ( sel . from ) . to < sel . to && view . docView . lineHasWidget ( sel . to ) &&
150142 view . inputState . insertingTextAt > Date . now ( ) - 50 ) {
151143 // For a cross-line insertion, Chrome and Safari will crudely take
152144 // the text of the line after the selection, flattening any
@@ -155,7 +147,7 @@ export function applyDOMChange(view: EditorView, domChange: DOMChange): boolean
155147 // replace of the text provided by the beforeinput event.
156148 change = {
157149 from : sel . from , to : sel . to ,
158- insert : view . state . toText ( view . inputState . insertingText )
150+ insert : state . toText ( view . inputState . insertingText )
159151 }
160152 } else if ( browser . chrome && change && change . from == change . to && change . from == sel . head &&
161153 change . insert . toString ( ) == "\n " && view . lineWrapping ) {
@@ -174,7 +166,7 @@ export function applyDOMChange(view: EditorView, domChange: DOMChange): boolean
174166 if ( view . inputState . lastSelectionOrigin == "select" ) scrollIntoView = true
175167 userEvent = view . inputState . lastSelectionOrigin !
176168 if ( userEvent == "select.pointer" )
177- newSel = skipAtomsForSelection ( view . state . facet ( atomicRanges ) . map ( f => f ( view ) ) , newSel )
169+ newSel = skipAtomsForSelection ( state . facet ( atomicRanges ) . map ( f => f ( view ) ) , newSel )
178170 }
179171 view . dispatch ( { selection : newSel , scrollIntoView, userEvent} )
180172 return true
0 commit comments