Skip to content

Commit 1d00df9

Browse files
committed
Make backspace across lines work in Chrome Android
(when there is a gutter) Issue codemirror#4637
1 parent cfcad60 commit 1d00df9

File tree

3 files changed

+31
-15
lines changed

3 files changed

+31
-15
lines changed

lib/codemirror.css

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
223223
cursor: default;
224224
z-index: 4;
225225
}
226-
.CodeMirror-gutter-wrapper {
227-
-webkit-user-select: none;
228-
-moz-user-select: none;
229-
user-select: none;
230-
}
226+
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
231227

232228
.CodeMirror-lines {
233229
cursor: text;

src/input/ContentEditableInput.js

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { gecko, ie_version } from "../util/browser"
1313
import { contains, range, removeChildrenAndAdd, selectInput } from "../util/dom"
1414
import { on, signalDOMEvent } from "../util/event"
1515
import { Delayed, lst, sel_dontScroll } from "../util/misc"
16+
import { chrome, android } from "../util/browser"
1617

1718
// CONTENTEDITABLE INPUT STYLE
1819

@@ -219,16 +220,28 @@ export default class ContentEditableInput {
219220
}
220221

221222
pollSelection() {
222-
if (!this.composing && this.readDOMTimeout == null && !this.gracePeriod && this.selectionChanged()) {
223-
let sel = window.getSelection(), cm = this.cm
224-
this.rememberSelection()
225-
let anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
226-
let head = domToPos(cm, sel.focusNode, sel.focusOffset)
227-
if (anchor && head) runInOp(cm, () => {
228-
setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll)
229-
if (anchor.bad || head.bad) cm.curOp.selectionChanged = true
230-
})
223+
if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) return
224+
let sel = window.getSelection(), cm = this.cm
225+
// On Android Chrome (version 56, at least), backspacing into an
226+
// uneditable block element will put the cursor in that element,
227+
// and then, because it's not editable, hide the virtual keyboard.
228+
// Because Android doesn't allow us to actually detect backspace
229+
// presses in a sane way, this code checks for when that happens
230+
// and simulates a backspace press in this case.
231+
if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
232+
this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs})
233+
this.blur()
234+
this.focus()
235+
return
231236
}
237+
if (this.composing) return
238+
this.rememberSelection()
239+
let anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
240+
let head = domToPos(cm, sel.focusNode, sel.focusOffset)
241+
if (anchor && head) runInOp(cm, () => {
242+
setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll)
243+
if (anchor.bad || head.bad) cm.curOp.selectionChanged = true
244+
})
232245
}
233246

234247
pollContent() {
@@ -370,6 +383,12 @@ function posToDOM(cm, pos) {
370383
return result
371384
}
372385

386+
function isInGutter(node) {
387+
for (let scan = node; scan; scan = scan.parentNode)
388+
if (/CodeMirror-gutter-wrapper/.test(scan.className)) return true
389+
return false
390+
}
391+
373392
function badPos(pos, bad) { if (bad) pos.bad = true; return pos }
374393

375394
function domTextBetween(cm, from, to, fromLine, toLine) {

src/util/browser.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ export let mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent)
1818
export let phantom = /PhantomJS/.test(userAgent)
1919

2020
export let ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent)
21+
export let android = /Android/.test(userAgent)
2122
// This is woefully incomplete. Suggestions for alternative methods welcome.
22-
export let mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent)
23+
export let mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent)
2324
export let mac = ios || /Mac/.test(platform)
2425
export let chromeOS = /\bCrOS\b/.test(userAgent)
2526
export let windows = /win/i.test(platform)

0 commit comments

Comments
 (0)