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:
committed by
Ian Storm Taylor
parent
21d0f4a233
commit
6d637f37a2
@@ -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)
|
||||
|
||||
|
Reference in New Issue
Block a user