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

fix selection operations being duplicated (#2023)

#### Is this adding or improving a _feature_ or fixing a _bug_?

Bug.

#### What's the new behavior?

Fixes selection operations from being duplicated.

#### How does this change work?

Previously the selection properties were compared by reference, but paths are immutable `List` objects, which always show up as having changed, resulting in extra selection operations that without any real changes. We now use `Immutable.is` to remove those duplicates, fixing the undo history stack.

#### Have you checked that...?

<!-- 
Please run through this checklist for your pull request: 
-->

* [x] The new code matches the existing patterns and styles.
* [x] The tests pass with `yarn test`.
* [x] The linter passes with `yarn lint`. (Fix errors with `yarn prettier`.)
* [x] The relevant examples still work. (Run examples with `yarn watch`.)

#### Does this fix any issues or need any specific reviewers?

Fixes: #2006
This commit is contained in:
Ian Storm Taylor
2018-08-01 11:55:45 -07:00
committed by GitHub
parent 1748a4b0c1
commit 5e6d376501
4 changed files with 22 additions and 16 deletions

View File

@@ -102,14 +102,14 @@ const TabList = styled('div')`
} }
` `
const Tab = styled(RouterLink)` const Tab = styled(({ active, ...props }) => <RouterLink {...props} />)`
display: inline-block; display: inline-block;
margin-bottom: 0.2em; margin-bottom: 0.2em;
padding: 0.2em 0.5em; padding: 0.2em 0.5em;
border-radius: 0.2em; border-radius: 0.2em;
text-decoration: none; text-decoration: none;
color: ${props => (props.active ? 'white' : '#777')}; color: ${p => (p.active ? 'white' : '#777')};
background: ${props => (props.active ? '#333' : 'transparent')}; background: ${p => (p.active ? '#333' : 'transparent')};
&:hover { &:hover {
background: #333; background: #333;

View File

@@ -347,6 +347,7 @@ function AfterPlugin() {
const entire = selection const entire = selection
.moveAnchorTo(point.key, start) .moveAnchorTo(point.key, start)
.moveFocusTo(point.key, end) .moveFocusTo(point.key, end)
.normalize(document)
// Change the current value to have the leaf's text replaced. // Change the current value to have the leaf's text replaced.
change.insertTextAtRange(entire, textContent, leaf.marks).select(corrected) change.insertTextAtRange(entire, textContent, leaf.marks).select(corrected)

View File

@@ -60,7 +60,7 @@ function findRange(native, value) {
} }
} }
const range = Range.create({ let range = Range.create({
anchorKey: anchor.key, anchorKey: anchor.key,
anchorOffset: anchor.offset, anchorOffset: anchor.offset,
focusKey: focus.key, focusKey: focus.key,
@@ -69,6 +69,7 @@ function findRange(native, value) {
isFocused: true, isFocused: true,
}) })
range = range.normalize(value.document)
return range return range
} }

View File

@@ -1,3 +1,4 @@
import { is } from 'immutable'
import isEmpty from 'is-empty' import isEmpty from 'is-empty'
import pick from 'lodash/pick' import pick from 'lodash/pick'
@@ -20,45 +21,48 @@ const Changes = {}
Changes.select = (change, properties, options = {}) => { Changes.select = (change, properties, options = {}) => {
properties = Range.createProperties(properties) properties = Range.createProperties(properties)
const { snapshot = false } = options const { snapshot = false } = options
const { value } = change const { value } = change
const { document, selection } = value const { document, selection } = value
const props = {} const props = {}
const sel = selection.toJSON()
const next = selection.merge(properties).normalize(document) const next = selection.merge(properties).normalize(document)
// Re-compute the properties, to ensure that we get their normalized values.
properties = pick(next, Object.keys(properties)) properties = pick(next, Object.keys(properties))
// Remove any properties that are already equal to the current selection. And // Remove any properties that are already equal to the current selection. And
// create a dictionary of the previous values for all of the properties that // create a dictionary of the previous values for all of the properties that
// are being changed, for the inverse operation. // are being changed, for the inverse operation.
for (const k in properties) { for (const k in properties) {
if (snapshot == false && properties[k] == sel[k]) continue if (snapshot === true || !is(properties[k], selection[k])) {
props[k] = properties[k] props[k] = properties[k]
}
} }
// If the selection moves, clear any marks, unless the new selection // If the selection moves, clear any marks, unless the new selection
// properties change the marks in some way. // properties change the marks in some way.
const moved = ['anchorKey', 'anchorOffset', 'focusKey', 'focusOffset'].some( if (
p => props.hasOwnProperty(p) selection.marks &&
) !props.marks &&
(props.hasOwnProperty('anchorKey') ||
if (sel.marks && properties.marks == sel.marks && moved) { props.hasOwnProperty('anchorOffset') ||
props.hasOwnProperty('focusKey') ||
props.hasOwnProperty('focusOffset'))
) {
props.marks = null props.marks = null
} }
// If there are no new properties to set, abort. // If there are no new properties to set, abort to avoid extra operations.
if (isEmpty(props)) { if (isEmpty(props)) {
return return
} }
// Apply the operation.
change.applyOperation( change.applyOperation(
{ {
type: 'set_selection', type: 'set_selection',
value, value,
properties: props, properties: props,
selection: sel, selection: selection.toJSON(),
}, },
snapshot ? { skip: false, merge: false } : {} snapshot ? { skip: false, merge: false } : {}
) )