mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-26 00:27:28 +02:00
fix selection behavior around inline nodes
This commit is contained in:
@@ -10,7 +10,6 @@ import Transfer from '../utils/transfer'
|
|||||||
import TYPES from '../constants/types'
|
import TYPES from '../constants/types'
|
||||||
import getWindow from 'get-window'
|
import getWindow from 'get-window'
|
||||||
import keycode from 'keycode'
|
import keycode from 'keycode'
|
||||||
import noop from '../utils/noop'
|
|
||||||
import { IS_FIREFOX, IS_MAC } from '../constants/environment'
|
import { IS_FIREFOX, IS_MAC } from '../constants/environment'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -656,7 +655,7 @@ class Content extends React.Component {
|
|||||||
const anchorInline = document.getClosestInline(anchor.key)
|
const anchorInline = document.getClosestInline(anchor.key)
|
||||||
const focusInline = document.getClosestInline(focus.key)
|
const focusInline = document.getClosestInline(focus.key)
|
||||||
|
|
||||||
if (anchorInline && anchor.offset == anchorText.length) {
|
if (anchorInline && !anchorInline.isVoid && anchor.offset == anchorText.length) {
|
||||||
const block = document.getClosestBlock(anchor.key)
|
const block = document.getClosestBlock(anchor.key)
|
||||||
const next = block.getNextText(anchor.key)
|
const next = block.getNextText(anchor.key)
|
||||||
if (next) {
|
if (next) {
|
||||||
@@ -665,7 +664,7 @@ class Content extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (focusInline && focus.offset == focusText.length) {
|
if (focusInline && !focusInline.isVoid && focus.offset == focusText.length) {
|
||||||
const block = document.getClosestBlock(focus.key)
|
const block = document.getClosestBlock(focus.key)
|
||||||
const next = block.getNextText(focus.key)
|
const next = block.getNextText(focus.key)
|
||||||
if (next) {
|
if (next) {
|
||||||
|
@@ -4,6 +4,7 @@ import CorePlugin from '../plugins/core'
|
|||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Schema from '../models/schema'
|
import Schema from '../models/schema'
|
||||||
|
import State from '../models/state'
|
||||||
import noop from '../utils/noop'
|
import noop from '../utils/noop'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,7 +59,7 @@ class Editor extends React.Component {
|
|||||||
readOnly: React.PropTypes.bool,
|
readOnly: React.PropTypes.bool,
|
||||||
schema: React.PropTypes.object,
|
schema: React.PropTypes.object,
|
||||||
spellCheck: React.PropTypes.bool,
|
spellCheck: React.PropTypes.bool,
|
||||||
state: React.PropTypes.object.isRequired,
|
state: React.PropTypes.instanceOf(State).isRequired,
|
||||||
style: React.PropTypes.object
|
style: React.PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -4,7 +4,6 @@ import Character from '../models/character'
|
|||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import Placeholder from '../components/placeholder'
|
import Placeholder from '../components/placeholder'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import String from '../utils/string'
|
|
||||||
import getWindow from 'get-window'
|
import getWindow from 'get-window'
|
||||||
import { IS_MAC } from '../constants/environment'
|
import { IS_MAC } from '../constants/environment'
|
||||||
|
|
||||||
@@ -455,7 +454,10 @@ function Plugin(options = {}) {
|
|||||||
/**
|
/**
|
||||||
* On `left` key down, move backward.
|
* On `left` key down, move backward.
|
||||||
*
|
*
|
||||||
* COMPAT: This is required to solve for the case where an inline void node is
|
* COMPAT: This is required to make navigating with the left arrow work when
|
||||||
|
* a void node is selected.
|
||||||
|
*
|
||||||
|
* COMPAT: This is also required to solve for the case where an inline node is
|
||||||
* surrounded by empty text nodes with zero-width spaces in them. Without this
|
* surrounded by empty text nodes with zero-width spaces in them. Without this
|
||||||
* the zero-width spaces will cause two arrow keys to jump to the next text.
|
* the zero-width spaces will cause two arrow keys to jump to the next text.
|
||||||
*
|
*
|
||||||
@@ -473,17 +475,33 @@ function Plugin(options = {}) {
|
|||||||
const { document, startKey, startText } = state
|
const { document, startKey, startText } = state
|
||||||
const hasVoidParent = document.hasVoidParent(startKey)
|
const hasVoidParent = document.hasVoidParent(startKey)
|
||||||
|
|
||||||
if (
|
// If the current text node is empty, or we're inside a void parent, we're
|
||||||
startText.text == '' ||
|
// going to need to handle the selection behavior.
|
||||||
hasVoidParent
|
if (startText.text == '' || hasVoidParent) {
|
||||||
) {
|
|
||||||
const previousText = document.getPreviousText(startKey)
|
|
||||||
if (!previousText) return
|
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
const previous = document.getPreviousText(startKey)
|
||||||
|
|
||||||
|
// If there's no previous text node in the document, abort.
|
||||||
|
if (!previous) return
|
||||||
|
|
||||||
|
// If the previous text is in the current block, and inside a non-void
|
||||||
|
// inline node, move one character into the inline node.
|
||||||
|
const { startBlock } = state
|
||||||
|
const previousBlock = document.getClosestBlock(previous.key)
|
||||||
|
const previousInline = document.getClosestInline(previous.key)
|
||||||
|
|
||||||
|
if (previousBlock == startBlock && previousInline && !previousInline.isVoid) {
|
||||||
|
return state
|
||||||
|
.transform()
|
||||||
|
.collapseToEndOf(previous)
|
||||||
|
.moveBackward(1)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, move to the end of the previous node.
|
||||||
return state
|
return state
|
||||||
.transform()
|
.transform()
|
||||||
.collapseToEndOf(previousText)
|
.collapseToEndOf(previous)
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -491,10 +509,18 @@ function Plugin(options = {}) {
|
|||||||
/**
|
/**
|
||||||
* On `right` key down, move forward.
|
* On `right` key down, move forward.
|
||||||
*
|
*
|
||||||
* COMPAT: This is required to solve for the case where an inline void node is
|
* COMPAT: This is required to make navigating with the right arrow work when
|
||||||
|
* a void node is selected.
|
||||||
|
*
|
||||||
|
* COMPAT: This is also required to solve for the case where an inline node is
|
||||||
* surrounded by empty text nodes with zero-width spaces in them. Without this
|
* surrounded by empty text nodes with zero-width spaces in them. Without this
|
||||||
* the zero-width spaces will cause two arrow keys to jump to the next text.
|
* the zero-width spaces will cause two arrow keys to jump to the next text.
|
||||||
*
|
*
|
||||||
|
* COMPAT: In Chrome & Safari, selections that are at the zero offset of
|
||||||
|
* an inline node will be automatically replaced to be at the last offset
|
||||||
|
* of a previous inline node, which screws us up, so we never want to set the
|
||||||
|
* selection to the very start of an inline node here. (2016/11/29)
|
||||||
|
*
|
||||||
* @param {Event} e
|
* @param {Event} e
|
||||||
* @param {Object} data
|
* @param {Object} data
|
||||||
* @param {State} state
|
* @param {State} state
|
||||||
@@ -509,24 +535,43 @@ function Plugin(options = {}) {
|
|||||||
const { document, startKey, startText } = state
|
const { document, startKey, startText } = state
|
||||||
const hasVoidParent = document.hasVoidParent(startKey)
|
const hasVoidParent = document.hasVoidParent(startKey)
|
||||||
|
|
||||||
if (
|
// If the current text node is empty, or we're inside a void parent, we're
|
||||||
startText.text == '' ||
|
// going to need to handle the selection behavior.
|
||||||
hasVoidParent
|
if (startText.text == '' || hasVoidParent) {
|
||||||
) {
|
|
||||||
const nextText = document.getNextText(startKey)
|
|
||||||
if (!nextText) return state
|
|
||||||
|
|
||||||
// COMPAT: In Chrome & Safari, selections that are at the zero offset of
|
|
||||||
// an inline node will be automatically replaced to be at the last offset
|
|
||||||
// of a previous inline node, which screws us up, so we always want to set
|
|
||||||
// it to the end of the node. (2016/11/29)
|
|
||||||
const hasNextVoidParent = document.hasVoidParent(nextText.key)
|
|
||||||
const method = hasNextVoidParent ? 'collapseToEndOf' : 'collapseToStartOf'
|
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
const next = document.getNextText(startKey)
|
||||||
|
|
||||||
|
// If there's no next text node in the document, abort.
|
||||||
|
if (!next) return state
|
||||||
|
|
||||||
|
// If the next text is inside a void node, move to the end of it.
|
||||||
|
const isInVoid = document.hasVoidParent(next.key)
|
||||||
|
|
||||||
|
if (isInVoid) {
|
||||||
|
return state
|
||||||
|
.transform()
|
||||||
|
.collapseToEndOf(next)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the next text is in the current block, and inside an inline node,
|
||||||
|
// move one character into the inline node.
|
||||||
|
const { startBlock } = state
|
||||||
|
const nextBlock = document.getClosestBlock(next.key)
|
||||||
|
const nextInline = document.getClosestInline(next.key)
|
||||||
|
|
||||||
|
if (nextBlock == startBlock && nextInline) {
|
||||||
|
return state
|
||||||
|
.transform()
|
||||||
|
.collapseToStartOf(next)
|
||||||
|
.moveForward(1)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, move to the start of the next text node.
|
||||||
return state
|
return state
|
||||||
.transform()
|
.transform()
|
||||||
[method](nextText)
|
.collapseToStartOf(next)
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user