mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-30 18:39:51 +02:00
fix selection setting for history
This commit is contained in:
@@ -99,6 +99,16 @@ class Selection extends new Record(DEFAULTS) {
|
|||||||
return this.isBackward == null ? null : !this.isBackward
|
return this.isBackward == null ? null : !this.isBackward
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the selection's keys are not set.
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
get isUnset() {
|
||||||
|
return this.anchorKey == null || this.focusKey == null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the start key.
|
* Get the start key.
|
||||||
*
|
*
|
||||||
@@ -281,19 +291,18 @@ class Selection extends new Record(DEFAULTS) {
|
|||||||
const { isCollapsed } = selection
|
const { isCollapsed } = selection
|
||||||
let { anchorKey, anchorOffset, focusKey, focusOffset, isBackward } = selection
|
let { anchorKey, anchorOffset, focusKey, focusOffset, isBackward } = selection
|
||||||
|
|
||||||
// If the selection isn't formed yet or is malformed, set it to the
|
// If the selection isn't formed yet or is malformed, ensure that it is
|
||||||
// beginning of the node.
|
// properly zeroed out.
|
||||||
if (
|
if (
|
||||||
anchorKey == null ||
|
anchorKey == null ||
|
||||||
focusKey == null ||
|
focusKey == null ||
|
||||||
!node.hasDescendant(anchorKey) ||
|
!node.hasDescendant(anchorKey) ||
|
||||||
!node.hasDescendant(focusKey)
|
!node.hasDescendant(focusKey)
|
||||||
) {
|
) {
|
||||||
const first = node.getTexts().first()
|
|
||||||
return selection.merge({
|
return selection.merge({
|
||||||
anchorKey: first.key,
|
anchorKey: null,
|
||||||
anchorOffset: 0,
|
anchorOffset: 0,
|
||||||
focusKey: first.key,
|
focusKey: null,
|
||||||
focusOffset: 0,
|
focusOffset: 0,
|
||||||
isBackward: false
|
isBackward: false
|
||||||
})
|
})
|
||||||
|
@@ -42,9 +42,16 @@ class State extends new Record(DEFAULTS) {
|
|||||||
|
|
||||||
static create(properties = {}) {
|
static create(properties = {}) {
|
||||||
if (properties instanceof State) return properties
|
if (properties instanceof State) return properties
|
||||||
properties.document = Document.create(properties.document)
|
|
||||||
properties.selection = Selection.create(properties.selection).normalize(properties.document)
|
let document = Document.create(properties.document)
|
||||||
return new State(properties)
|
let selection = Selection.create(properties.selection)
|
||||||
|
|
||||||
|
if (selection.isUnset) {
|
||||||
|
const text = document.getTexts().first()
|
||||||
|
selection = selection.collapseToStartOf(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new State({ document, selection })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -281,15 +281,17 @@ function setSelection(state, operation) {
|
|||||||
let properties = { ...operation.properties }
|
let properties = { ...operation.properties }
|
||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
|
|
||||||
if (properties.anchorPath) {
|
if (properties.anchorPath !== undefined) {
|
||||||
const anchorNode = document.assertPath(properties.anchorPath)
|
properties.anchorKey = properties.anchorPath === null
|
||||||
properties.anchorKey = anchorNode.key
|
? null
|
||||||
|
: document.assertPath(properties.anchorPath).key
|
||||||
delete properties.anchorPath
|
delete properties.anchorPath
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties.focusPath) {
|
if (properties.focusPath !== undefined) {
|
||||||
const focusNode = document.assertPath(properties.focusPath)
|
properties.focusKey = properties.focusPath === null
|
||||||
properties.focusKey = focusNode.key
|
? null
|
||||||
|
: document.assertPath(properties.focusPath).key
|
||||||
delete properties.focusPath
|
delete properties.focusPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -80,6 +80,7 @@ export function _delete(transform) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
|
.unsetSelection()
|
||||||
.deleteAtRange(selection)
|
.deleteAtRange(selection)
|
||||||
.moveTo(after)
|
.moveTo(after)
|
||||||
}
|
}
|
||||||
@@ -154,6 +155,7 @@ export function deleteBackward(transform, n = 1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
|
.unsetSelection()
|
||||||
.deleteBackwardAtRange(selection, n)
|
.deleteBackwardAtRange(selection, n)
|
||||||
.moveTo(after)
|
.moveTo(after)
|
||||||
}
|
}
|
||||||
@@ -213,6 +215,7 @@ export function deleteForward(transform, n = 1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
|
.unsetSelection()
|
||||||
.deleteForwardAtRange(selection, n)
|
.deleteForwardAtRange(selection, n)
|
||||||
.moveTo(after)
|
.moveTo(after)
|
||||||
}
|
}
|
||||||
@@ -230,6 +233,7 @@ export function insertBlock(transform, block) {
|
|||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
const keys = document.getTexts().map(text => text.key)
|
const keys = document.getTexts().map(text => text.key)
|
||||||
|
|
||||||
|
transform.unsetSelection()
|
||||||
transform.insertBlockAtRange(selection, block)
|
transform.insertBlockAtRange(selection, block)
|
||||||
state = transform.state
|
state = transform.state
|
||||||
document = state.document
|
document = state.document
|
||||||
@@ -258,6 +262,7 @@ export function insertFragment(transform, fragment) {
|
|||||||
const lastInline = fragment.getClosestInline(lastText)
|
const lastInline = fragment.getClosestInline(lastText)
|
||||||
const beforeTexts = document.getTexts()
|
const beforeTexts = document.getTexts()
|
||||||
|
|
||||||
|
transform.unsetSelection()
|
||||||
transform.insertFragmentAtRange(selection, fragment)
|
transform.insertFragmentAtRange(selection, fragment)
|
||||||
state = transform.state
|
state = transform.state
|
||||||
document = state.document
|
document = state.document
|
||||||
@@ -306,6 +311,7 @@ export function insertInline(transform, inline) {
|
|||||||
const hasVoid = document.hasVoidParent(startText)
|
const hasVoid = document.hasVoidParent(startText)
|
||||||
const keys = document.getTexts().map(text => text.key)
|
const keys = document.getTexts().map(text => text.key)
|
||||||
|
|
||||||
|
transform.unsetSelection()
|
||||||
transform.insertInlineAtRange(selection, inline)
|
transform.insertInlineAtRange(selection, inline)
|
||||||
state = transform.state
|
state = transform.state
|
||||||
document = state.document
|
document = state.document
|
||||||
@@ -353,6 +359,7 @@ export function insertText(transform, text, marks) {
|
|||||||
marks = marks || selection.marks
|
marks = marks || selection.marks
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
|
.unsetSelection()
|
||||||
.insertTextAtRange(selection, text, marks)
|
.insertTextAtRange(selection, text, marks)
|
||||||
.moveTo(after)
|
.moveTo(after)
|
||||||
}
|
}
|
||||||
@@ -397,6 +404,7 @@ export function splitBlock(transform, depth = 1) {
|
|||||||
let { state } = transform
|
let { state } = transform
|
||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
|
|
||||||
|
transform.unsetSelection()
|
||||||
transform.splitBlockAtRange(selection, depth)
|
transform.splitBlockAtRange(selection, depth)
|
||||||
|
|
||||||
state = transform.state
|
state = transform.state
|
||||||
@@ -423,6 +431,7 @@ export function splitInline(transform, depth = Infinity) {
|
|||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
let after = selection
|
let after = selection
|
||||||
|
|
||||||
|
transform.unsetSelection()
|
||||||
transform.splitInlineAtRange(selection, depth)
|
transform.splitInlineAtRange(selection, depth)
|
||||||
state = transform.state
|
state = transform.state
|
||||||
document = state.document
|
document = state.document
|
||||||
@@ -551,6 +560,7 @@ export function wrapInline(transform, properties) {
|
|||||||
const { startKey } = selection
|
const { startKey } = selection
|
||||||
const previous = document.getPreviousText(startKey)
|
const previous = document.getPreviousText(startKey)
|
||||||
|
|
||||||
|
transform.unsetSelection()
|
||||||
transform.wrapInlineAtRange(selection, properties)
|
transform.wrapInlineAtRange(selection, properties)
|
||||||
state = transform.state
|
state = transform.state
|
||||||
document = state.document
|
document = state.document
|
||||||
@@ -612,6 +622,7 @@ export function wrapText(transform, prefix, suffix = prefix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
|
.unsetSelection()
|
||||||
.wrapTextAtRange(selection, prefix, suffix)
|
.wrapTextAtRange(selection, prefix, suffix)
|
||||||
.moveTo(after)
|
.moveTo(after)
|
||||||
}
|
}
|
||||||
|
@@ -124,6 +124,7 @@ import {
|
|||||||
moveTo,
|
moveTo,
|
||||||
moveToOffsets,
|
moveToOffsets,
|
||||||
moveToRangeOf,
|
moveToRangeOf,
|
||||||
|
unsetSelection,
|
||||||
} from './on-selection'
|
} from './on-selection'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -267,6 +268,7 @@ export default {
|
|||||||
moveTo,
|
moveTo,
|
||||||
moveToOffsets,
|
moveToOffsets,
|
||||||
moveToRangeOf,
|
moveToRangeOf,
|
||||||
|
unsetSelection,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* History.
|
* History.
|
||||||
|
@@ -364,6 +364,7 @@ export function moveForward(transform, n) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export function moveTo(transform, properties) {
|
export function moveTo(transform, properties) {
|
||||||
|
debugger
|
||||||
return transform.setSelectionOperation(properties)
|
return transform.setSelectionOperation(properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,3 +399,21 @@ export function moveToRangeOf(transform, start, end) {
|
|||||||
const sel = selection.moveToRangeOf(start, end).normalize(document)
|
const sel = selection.moveToRangeOf(start, end).normalize(document)
|
||||||
return transform.setSelectionOperation(sel)
|
return transform.setSelectionOperation(sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unset the selection, removing an association to a node.
|
||||||
|
*
|
||||||
|
* @param {Transform} transform
|
||||||
|
* @return {Transform}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function unsetSelection(transform) {
|
||||||
|
return transform.setSelectionOperation({
|
||||||
|
anchorKey: null,
|
||||||
|
anchorOffset: 0,
|
||||||
|
focusKey: null,
|
||||||
|
focusOffset: 0,
|
||||||
|
isFocused: false,
|
||||||
|
isBackward: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -361,39 +361,53 @@ export function setSelectionOperation(transform, properties) {
|
|||||||
const { document, selection } = state
|
const { document, selection } = state
|
||||||
const prevProps = {}
|
const prevProps = {}
|
||||||
|
|
||||||
if (properties.marks == selection.marks) {
|
// If the current selection has marks, and the new selection doesn't change
|
||||||
|
// them in some way, they are old and should be removed.
|
||||||
|
if (selection.marks && properties.marks == selection.marks) {
|
||||||
properties.marks = null
|
properties.marks = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a dictionary of the previous values for all of the properties that
|
||||||
|
// are being changed, for the inverse operation.
|
||||||
for (const k in properties) {
|
for (const k in properties) {
|
||||||
prevProps[k] = selection[k]
|
prevProps[k] = selection[k]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve the selection keys into paths.
|
||||||
if (properties.anchorKey) {
|
if (properties.anchorKey) {
|
||||||
properties.anchorPath = document.getPath(properties.anchorKey)
|
properties.anchorPath = document.getPath(properties.anchorKey)
|
||||||
prevProps.anchorPath = document.getPath(prevProps.anchorKey)
|
|
||||||
delete properties.anchorKey
|
delete properties.anchorKey
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevProps.anchorKey) {
|
||||||
|
prevProps.anchorPath = document.getPath(prevProps.anchorKey)
|
||||||
delete prevProps.anchorKey
|
delete prevProps.anchorKey
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties.focusKey) {
|
if (properties.focusKey) {
|
||||||
properties.focusPath = document.getPath(properties.focusKey)
|
properties.focusPath = document.getPath(properties.focusKey)
|
||||||
prevProps.focusPath = document.getPath(prevProps.focusKey)
|
|
||||||
delete properties.focusKey
|
delete properties.focusKey
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevProps.focusKey) {
|
||||||
|
prevProps.focusPath = document.getPath(prevProps.focusKey)
|
||||||
delete prevProps.focusKey
|
delete prevProps.focusKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define an inverse of the operation for undoing.
|
||||||
const inverse = [{
|
const inverse = [{
|
||||||
type: 'set_selection',
|
type: 'set_selection',
|
||||||
properties: prevProps
|
properties: prevProps
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
// Define the operation.
|
||||||
const operation = {
|
const operation = {
|
||||||
type: 'set_selection',
|
type: 'set_selection',
|
||||||
properties,
|
properties,
|
||||||
inverse,
|
inverse,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the operation.
|
||||||
return transform.applyOperation(operation)
|
return transform.applyOperation(operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -107,7 +107,7 @@ function markProperties(value = {}) {
|
|||||||
case 'object': {
|
case 'object': {
|
||||||
for (const k in value) {
|
for (const k in value) {
|
||||||
if (k == 'data') {
|
if (k == 'data') {
|
||||||
if (value[k] != null) ret[k] = Data.create(value[k])
|
if (value[k] !== undefined) ret[k] = Data.create(value[k])
|
||||||
} else {
|
} else {
|
||||||
ret[k] = value[k]
|
ret[k] = value[k]
|
||||||
}
|
}
|
||||||
@@ -138,10 +138,10 @@ function nodeProperties(value = {}) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'object': {
|
case 'object': {
|
||||||
if (value.isVoid != null) ret.isVoid = !!value.isVoid
|
if (value.isVoid !== undefined) ret.isVoid = !!value.isVoid
|
||||||
for (const k in value) {
|
for (const k in value) {
|
||||||
if (k == 'data') {
|
if (k == 'data') {
|
||||||
if (value[k] != null) ret[k] = Data.create(value[k])
|
if (value[k] !== undefined) ret[k] = Data.create(value[k])
|
||||||
} else {
|
} else {
|
||||||
ret[k] = value[k]
|
ret[k] = value[k]
|
||||||
}
|
}
|
||||||
@@ -188,12 +188,12 @@ function selectionProperties(value = {}) {
|
|||||||
|
|
||||||
switch (typeOf(value)) {
|
switch (typeOf(value)) {
|
||||||
case 'object': {
|
case 'object': {
|
||||||
if (value.anchorKey != null) ret.anchorKey = value.anchorKey
|
if (value.anchorKey !== undefined) ret.anchorKey = value.anchorKey
|
||||||
if (value.anchorOffset != null) ret.anchorOffset = value.anchorOffset
|
if (value.anchorOffset !== undefined) ret.anchorOffset = value.anchorOffset
|
||||||
if (value.focusKey != null) ret.focusKey = value.focusKey
|
if (value.focusKey !== undefined) ret.focusKey = value.focusKey
|
||||||
if (value.focusOffset != null) ret.focusOffset = value.focusOffset
|
if (value.focusOffset !== undefined) ret.focusOffset = value.focusOffset
|
||||||
if (value.isBackward != null) ret.isBackward = !!value.isBackward
|
if (value.isBackward !== undefined) ret.isBackward = !!value.isBackward
|
||||||
if (value.isFocused != null) ret.isFocused = !!value.isFocused
|
if (value.isFocused !== undefined) ret.isFocused = !!value.isFocused
|
||||||
if (value.marks !== undefined) ret.marks = value.marks
|
if (value.marks !== undefined) ret.marks = value.marks
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user