1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-16 04:04:06 +02:00

Bugfix: Fixes issue where focusing on editor always placed caret at offset 0 (#2995)

* Revert "fix(firefox): fixed the bug that happens when changing the focus from one field to another (#2236)"

This reverts commit 6aba4260f8.

* Fixes issue where focusing on editor always placed caret at offset 0

* Inlines `selectionsEqual` logic and adds some comments
This commit is contained in:
kay delaney
2019-09-27 15:30:29 +01:00
committed by Ian Storm Taylor
parent 21d0f4a233
commit 6d637f37a2

View File

@@ -105,6 +105,7 @@ class Content extends React.Component {
nodeRef: React.createRef(),
nodeRefs: {},
contentKey: 0,
nativeSelection: {}, // Native selection object stored to check if `onNativeSelectionChange` has triggered yet
}
/**
@@ -237,7 +238,35 @@ class Content extends React.Component {
// If the Slate selection is unset, but the DOM selection has a range
// selected in the editor, we need to remove the range.
if (selection.isUnset && rangeCount && this.isInEditor(anchorNode)) {
// However we should _not_ remove the range if the selection as
// reported by `getSelection` is not equal to `this.tmp.nativeSelection`
// as this suggests `onNativeSelectionChange` has not triggered yet (which can occur in Firefox)
// See: https://github.com/ianstormtaylor/slate/pull/2995
const propsToCompare = [
'anchorNode',
'anchorOffset',
'focusNode',
'focusOffset',
'isCollapsed',
'rangeCount',
'type',
]
let selectionsEqual = true
for (const prop of propsToCompare) {
if (this.tmp.nativeSelection[prop] !== native[prop]) {
selectionsEqual = false
}
}
if (
selection.isUnset &&
rangeCount &&
this.isInEditor(anchorNode) &&
selectionsEqual
) {
removeAllRanges(native)
updated = true
}
@@ -288,39 +317,43 @@ class Content extends React.Component {
// Otherwise, set the `isUpdatingSelection` flag and update the selection.
updated = true
this.tmp.isUpdatingSelection = true
removeAllRanges(native)
if (!IS_FIREFOX) {
removeAllRanges(native)
// COMPAT: IE 11 does not support `setBaseAndExtent`. (2018/11/07)
if (native.setBaseAndExtent) {
// COMPAT: Since the DOM range has no concept of backwards/forwards
// we need to check and do the right thing here.
if (isBackward) {
native.setBaseAndExtent(
range.endContainer,
range.endOffset,
range.startContainer,
range.startOffset
)
} else {
native.setBaseAndExtent(
range.startContainer,
range.startOffset,
range.endContainer,
range.endOffset
)
}
// COMPAT: IE 11 does not support `setBaseAndExtent`. (2018/11/07)
if (native.setBaseAndExtent) {
// COMPAT: Since the DOM range has no concept of backwards/forwards
// we need to check and do the right thing here.
if (isBackward) {
native.setBaseAndExtent(
range.endContainer,
range.endOffset,
range.startContainer,
range.startOffset
)
} else {
native.addRange(range)
native.setBaseAndExtent(
range.startContainer,
range.startOffset,
range.endContainer,
range.endOffset
)
}
} else {
native.addRange(range)
}
// Scroll to the selection, in case it's out of view.
scrollToSelection(native)
// Then unset the `isUpdatingSelection` flag after a delay.
// Then unset the `isUpdatingSelection` flag after a delay, to ensure that
// it is still set when selection-related events from updating it fire.
setTimeout(() => {
// COMPAT: In Firefox, it's not enough to create a range, you also need
// to focus the contenteditable element too. (2016/11/16)
if (IS_FIREFOX && this.ref.current) {
this.ref.current.focus()
}
this.tmp.isUpdatingSelection = false
debug.update('updateSelection:setTimeout', {
@@ -355,6 +388,12 @@ class Content extends React.Component {
let el
try {
// COMPAT: In Firefox, sometimes the node can be comment which doesn't
// have .closest and it crashes.
if (target.nodeType === 8) {
return false
}
// COMPAT: Text nodes don't have `isContentEditable` property. So, when
// `target` is a text node use its parent node for check.
el = target.nodeType === 3 ? target.parentNode : target
@@ -481,12 +520,24 @@ class Content extends React.Component {
const window = getWindow(event.target)
const { activeElement } = window.document
const native = window.getSelection()
debug.update('onNativeSelectionChange', {
anchorOffset: window.getSelection().anchorOffset,
anchorOffset: native.anchorOffset,
})
if (activeElement !== this.ref.current) return
this.tmp.nativeSelection = {
anchorNode: native.anchorNode,
anchorOffset: native.anchorOffset,
focusNode: native.focusNode,
focusOffset: native.focusOffset,
isCollapsed: native.isCollapsed,
rangeCount: native.rangeCount,
type: native.type,
}
this.props.onEvent('onSelect', event)
}, 100)