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:
@@ -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) {
|
||||
|
@@ -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
|
||||
};
|
||||
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user