mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-24 16:02:55 +02:00
Avoid finding native selection focus position when selection is collapsed (#1100)
* Avoid finding native selection focus position when selection is collapsed. Use already calculated anchor position instead. Move code to get caret position from a selection point in `utils`. * Update content.js * Update get-caret-position.js
This commit is contained in:
committed by
Ian Storm Taylor
parent
5135f98845
commit
25d54e30b0
@@ -12,7 +12,7 @@ import Selection from '../models/selection'
|
|||||||
import SlateTypes from '../utils/prop-types'
|
import SlateTypes from '../utils/prop-types'
|
||||||
import extendSelection from '../utils/extend-selection'
|
import extendSelection from '../utils/extend-selection'
|
||||||
import findClosestNode from '../utils/find-closest-node'
|
import findClosestNode from '../utils/find-closest-node'
|
||||||
import findDeepestNode from '../utils/find-deepest-node'
|
import getCaretPosition from '../utils/get-caret-position'
|
||||||
import getHtmlFromNativePaste from '../utils/get-html-from-native-paste'
|
import getHtmlFromNativePaste from '../utils/get-html-from-native-paste'
|
||||||
import getPoint from '../utils/get-point'
|
import getPoint from '../utils/get-point'
|
||||||
import getTransferData from '../utils/get-transfer-data'
|
import getTransferData from '../utils/get-transfer-data'
|
||||||
@@ -147,7 +147,7 @@ class Content extends React.Component {
|
|||||||
|
|
||||||
updateSelection = () => {
|
updateSelection = () => {
|
||||||
const { editor, state } = this.props
|
const { editor, state } = this.props
|
||||||
const { document, selection } = state
|
const { selection } = state
|
||||||
const window = getWindow(this.element)
|
const window = getWindow(this.element)
|
||||||
const native = window.getSelection()
|
const native = window.getSelection()
|
||||||
|
|
||||||
@@ -168,49 +168,18 @@ class Content extends React.Component {
|
|||||||
if (selection.isUnset) return
|
if (selection.isUnset) return
|
||||||
|
|
||||||
// Otherwise, figure out which DOM nodes should be selected...
|
// Otherwise, figure out which DOM nodes should be selected...
|
||||||
const { anchorText, focusText } = state
|
const { anchorKey, anchorOffset, focusKey, focusOffset, isCollapsed } = selection
|
||||||
const { anchorKey, anchorOffset, focusKey, focusOffset } = selection
|
const anchor = getCaretPosition(anchorKey, anchorOffset, state, editor, this.element)
|
||||||
const schema = editor.getSchema()
|
const focus = isCollapsed
|
||||||
const anchorDecorators = document.getDescendantDecorators(anchorKey, schema)
|
? anchor
|
||||||
const focusDecorators = document.getDescendantDecorators(focusKey, schema)
|
: getCaretPosition(focusKey, focusOffset, state, editor, this.element)
|
||||||
const anchorRanges = anchorText.getRanges(anchorDecorators)
|
|
||||||
const focusRanges = focusText.getRanges(focusDecorators)
|
|
||||||
let a = 0
|
|
||||||
let f = 0
|
|
||||||
let anchorIndex
|
|
||||||
let focusIndex
|
|
||||||
let anchorOff
|
|
||||||
let focusOff
|
|
||||||
|
|
||||||
anchorRanges.forEach((range, i, ranges) => {
|
|
||||||
const { length } = range.text
|
|
||||||
a += length
|
|
||||||
if (a < anchorOffset) return
|
|
||||||
anchorIndex = i
|
|
||||||
anchorOff = anchorOffset - (a - length)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
focusRanges.forEach((range, i, ranges) => {
|
|
||||||
const { length } = range.text
|
|
||||||
f += length
|
|
||||||
if (f < focusOffset) return
|
|
||||||
focusIndex = i
|
|
||||||
focusOff = focusOffset - (f - length)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
const anchorSpan = this.element.querySelector(`[data-offset-key="${anchorKey}-${anchorIndex}"]`)
|
|
||||||
const focusSpan = this.element.querySelector(`[data-offset-key="${focusKey}-${focusIndex}"]`)
|
|
||||||
const anchorEl = findDeepestNode(anchorSpan)
|
|
||||||
const focusEl = findDeepestNode(focusSpan)
|
|
||||||
|
|
||||||
// If they are already selected, do nothing.
|
// If they are already selected, do nothing.
|
||||||
if (
|
if (
|
||||||
anchorEl == native.anchorNode &&
|
anchor.node == native.anchorNode &&
|
||||||
anchorOff == native.anchorOffset &&
|
anchor.offset == native.anchorOffset &&
|
||||||
focusEl == native.focusNode &&
|
focus.node == native.focusNode &&
|
||||||
focusOff == native.focusOffset
|
focus.offset == native.focusOffset
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -219,9 +188,9 @@ class Content extends React.Component {
|
|||||||
this.tmp.isSelecting = true
|
this.tmp.isSelecting = true
|
||||||
native.removeAllRanges()
|
native.removeAllRanges()
|
||||||
const range = window.document.createRange()
|
const range = window.document.createRange()
|
||||||
range.setStart(anchorEl, anchorOff)
|
range.setStart(anchor.node, anchor.offset)
|
||||||
native.addRange(range)
|
native.addRange(range)
|
||||||
extendSelection(native, focusEl, focusOff)
|
if (!isCollapsed) extendSelection(native, focus.node, focus.offset)
|
||||||
|
|
||||||
// Then unset the `isSelecting` flag after a delay.
|
// Then unset the `isSelecting` flag after a delay.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
45
src/utils/get-caret-position.js
Normal file
45
src/utils/get-caret-position.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import findDeepestNode from './find-deepest-node'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get caret position from selection point.
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @param {Number} offset
|
||||||
|
* @param {State} state
|
||||||
|
* @param {Editor} editor
|
||||||
|
* @param {Element} el
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getCaretPosition(key, offset, state, editor, el) {
|
||||||
|
const { document } = state
|
||||||
|
const text = document.getDescendant(key)
|
||||||
|
const schema = editor.getSchema()
|
||||||
|
const decorators = document.getDescendantDecorators(key, schema)
|
||||||
|
const ranges = text.getRanges(decorators)
|
||||||
|
|
||||||
|
let a = 0
|
||||||
|
let index
|
||||||
|
let off
|
||||||
|
|
||||||
|
ranges.forEach((range, i) => {
|
||||||
|
const { length } = range.text
|
||||||
|
a += length
|
||||||
|
if (a < offset) return
|
||||||
|
index = i
|
||||||
|
off = offset - (a - length)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
const span = el.querySelector(`[data-offset-key="${key}-${index}"]`)
|
||||||
|
const node = findDeepestNode(span)
|
||||||
|
return { node, offset: off }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export.
|
||||||
|
*
|
||||||
|
* @type {Function}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default getCaretPosition
|
Reference in New Issue
Block a user