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

fix selection behavior around inline nodes

This commit is contained in:
Ian Storm Taylor
2016-12-02 11:07:02 -08:00
parent 73cf5fe54f
commit 9c81ed9c47
3 changed files with 75 additions and 30 deletions

View File

@@ -10,7 +10,6 @@ import Transfer from '../utils/transfer'
import TYPES from '../constants/types'
import getWindow from 'get-window'
import keycode from 'keycode'
import noop from '../utils/noop'
import { IS_FIREFOX, IS_MAC } from '../constants/environment'
/**
@@ -656,7 +655,7 @@ class Content extends React.Component {
const anchorInline = document.getClosestInline(anchor.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 next = block.getNextText(anchor.key)
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 next = block.getNextText(focus.key)
if (next) {

View File

@@ -4,6 +4,7 @@ import CorePlugin from '../plugins/core'
import Debug from 'debug'
import React from 'react'
import Schema from '../models/schema'
import State from '../models/state'
import noop from '../utils/noop'
/**
@@ -58,7 +59,7 @@ class Editor extends React.Component {
readOnly: React.PropTypes.bool,
schema: React.PropTypes.object,
spellCheck: React.PropTypes.bool,
state: React.PropTypes.object.isRequired,
state: React.PropTypes.instanceOf(State).isRequired,
style: React.PropTypes.object
};

View File

@@ -4,7 +4,6 @@ import Character from '../models/character'
import Debug from 'debug'
import Placeholder from '../components/placeholder'
import React from 'react'
import String from '../utils/string'
import getWindow from 'get-window'
import { IS_MAC } from '../constants/environment'
@@ -455,7 +454,10 @@ function Plugin(options = {}) {
/**
* 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
* 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 hasVoidParent = document.hasVoidParent(startKey)
if (
startText.text == '' ||
hasVoidParent
) {
const previousText = document.getPreviousText(startKey)
if (!previousText) return
// If the current text node is empty, or we're inside a void parent, we're
// going to need to handle the selection behavior.
if (startText.text == '' || hasVoidParent) {
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
.transform()
.collapseToEndOf(previousText)
.collapseToEndOf(previous)
.apply()
}
}
@@ -491,10 +509,18 @@ function Plugin(options = {}) {
/**
* 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
* 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 {Object} data
* @param {State} state
@@ -509,24 +535,43 @@ function Plugin(options = {}) {
const { document, startKey, startText } = state
const hasVoidParent = document.hasVoidParent(startKey)
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'
// If the current text node is empty, or we're inside a void parent, we're
// going to need to handle the selection behavior.
if (startText.text == '' || hasVoidParent) {
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
.transform()
[method](nextText)
.collapseToStartOf(next)
.apply()
}
}