mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-28 09:29:49 +02:00
cleanup lots of selection code, get tests passing again
This commit is contained in:
@@ -3,19 +3,6 @@ import getLeafText from '../utils/get-leaf-text'
|
|||||||
import warn from '../utils/warn'
|
import warn from '../utils/warn'
|
||||||
import { Record } from 'immutable'
|
import { Record } from 'immutable'
|
||||||
|
|
||||||
/**
|
|
||||||
* Start-end-and-edge convenience methods to auto-generate.
|
|
||||||
*
|
|
||||||
* @type {Array}
|
|
||||||
*/
|
|
||||||
|
|
||||||
const EDGE_METHODS = [
|
|
||||||
'has%AtStartOf',
|
|
||||||
'has%AtEndOf',
|
|
||||||
'has%Between',
|
|
||||||
'has%In',
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default properties.
|
* Default properties.
|
||||||
*
|
*
|
||||||
@@ -422,38 +409,6 @@ class Selection extends new Record(DEFAULTS) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the end point to the start point.
|
|
||||||
*
|
|
||||||
* @return {Selection}
|
|
||||||
*/
|
|
||||||
|
|
||||||
collapseToStart() {
|
|
||||||
return this.merge({
|
|
||||||
anchorKey: this.startKey,
|
|
||||||
anchorOffset: this.startOffset,
|
|
||||||
focusKey: this.startKey,
|
|
||||||
focusOffset: this.startOffset,
|
|
||||||
isBackward: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the end point to the start point.
|
|
||||||
*
|
|
||||||
* @return {Selection}
|
|
||||||
*/
|
|
||||||
|
|
||||||
collapseToEnd() {
|
|
||||||
return this.merge({
|
|
||||||
anchorKey: this.endKey,
|
|
||||||
anchorOffset: this.endOffset,
|
|
||||||
focusKey: this.endKey,
|
|
||||||
focusOffset: this.endOffset,
|
|
||||||
isBackward: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move to the start of a `node`.
|
* Move to the start of a `node`.
|
||||||
*
|
*
|
||||||
@@ -590,45 +545,35 @@ class Selection extends new Record(DEFAULTS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the start point forward `n` characters.
|
* Move the anchor offset `n` characters.
|
||||||
*
|
*
|
||||||
* @param {Number} n (optional)
|
* @param {Number} n (optional)
|
||||||
* @return {Selection}
|
* @return {Selection}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
moveStartOffset(n = 1) {
|
moveAnchorOffset(n = 1) {
|
||||||
if (this.isBackward) {
|
const { anchorKey, focusKey, focusOffset } = this
|
||||||
|
const anchorOffset = this.anchorOffset + n
|
||||||
return this.merge({
|
return this.merge({
|
||||||
focusOffset: this.focusOffset + n,
|
anchorOffset,
|
||||||
isBackward: null
|
isBackward: anchorKey == focusKey ? anchorOffset > focusOffset : this.isBackward
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
return this.merge({
|
|
||||||
anchorOffset: this.anchorOffset + n,
|
|
||||||
isBackward: null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the end point forward `n` characters.
|
* Move the anchor offset `n` characters.
|
||||||
*
|
*
|
||||||
* @param {Number} n (optional)
|
* @param {Number} n (optional)
|
||||||
* @return {Selection}
|
* @return {Selection}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
moveEndOffset(n = 1) {
|
moveFocusOffset(n = 1) {
|
||||||
if (this.isBackward) {
|
const { focusKey, anchorKey, anchorOffset } = this
|
||||||
|
const focusOffset = this.focusOffset + n
|
||||||
return this.merge({
|
return this.merge({
|
||||||
anchorOffset: this.anchorOffset + n,
|
focusOffset,
|
||||||
isBackward: null
|
isBackward: focusKey == anchorKey ? anchorOffset > focusOffset : this.isBackward
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
return this.merge({
|
|
||||||
focusOffset: this.focusOffset + n,
|
|
||||||
isBackward: null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -724,14 +669,37 @@ class Selection extends new Record(DEFAULTS) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flip the selection.
|
||||||
|
*
|
||||||
|
* @return {Selection}
|
||||||
|
*/
|
||||||
|
|
||||||
|
flip() {
|
||||||
|
return this.merge({
|
||||||
|
anchorKey: this.focusKey,
|
||||||
|
anchorOffset: this.focusOffset,
|
||||||
|
focusKey: this.anchorKey,
|
||||||
|
focusOffset: this.anchorOffset,
|
||||||
|
isBackward: this.isBackward == null ? null : !this.isBackward,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add start, end and edge convenience methods.
|
* Add start, end and edge convenience methods.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
EDGE_METHODS.forEach((pattern) => {
|
[
|
||||||
const [ p, s ] = pattern.split('%')
|
['has', 'AtStartOf', true],
|
||||||
|
['has', 'AtEndOf', true],
|
||||||
|
['has', 'Between', true],
|
||||||
|
['has', 'In', true],
|
||||||
|
['collapseTo', ''],
|
||||||
|
['move', 'Offset'],
|
||||||
|
].forEach((opts) => {
|
||||||
|
const [ p, s, hasEdge ] = opts
|
||||||
const anchor = `${p}Anchor${s}`
|
const anchor = `${p}Anchor${s}`
|
||||||
const edge = `${p}Edge${s}`
|
const edge = `${p}Edge${s}`
|
||||||
const end = `${p}End${s}`
|
const end = `${p}End${s}`
|
||||||
@@ -750,9 +718,11 @@ EDGE_METHODS.forEach((pattern) => {
|
|||||||
: this[focus](...args)
|
: this[focus](...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasEdge) {
|
||||||
Selection.prototype[edge] = function (...args) {
|
Selection.prototype[edge] = function (...args) {
|
||||||
return this[anchor](...args) || this[focus](...args)
|
return this[anchor](...args) || this[focus](...args)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -104,7 +104,7 @@ function insertNode(state, operation) {
|
|||||||
function insertText(state, operation) {
|
function insertText(state, operation) {
|
||||||
const { path, offset, text, marks } = operation
|
const { path, offset, text, marks } = operation
|
||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
const { startKey, endKey, startOffset, endOffset } = selection
|
const { anchorKey, focusKey, anchorOffset, focusOffset } = selection
|
||||||
let node = document.assertPath(path)
|
let node = document.assertPath(path)
|
||||||
|
|
||||||
// Update the document
|
// Update the document
|
||||||
@@ -112,11 +112,11 @@ function insertText(state, operation) {
|
|||||||
document = document.updateDescendant(node)
|
document = document.updateDescendant(node)
|
||||||
|
|
||||||
// Update the selection
|
// Update the selection
|
||||||
if (startKey == node.key && startOffset >= offset) {
|
if (anchorKey == node.key && anchorOffset >= offset) {
|
||||||
selection = selection.moveStartOffset(text.length)
|
selection = selection.moveAnchorOffset(text.length)
|
||||||
}
|
}
|
||||||
if (endKey == node.key && endOffset >= offset) {
|
if (focusKey == node.key && focusOffset >= offset) {
|
||||||
selection = selection.moveEndOffset(text.length)
|
selection = selection.moveFocusOffset(text.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
state = state.merge({ document, selection })
|
state = state.merge({ document, selection })
|
||||||
@@ -287,15 +287,15 @@ function removeText(state, operation) {
|
|||||||
const { path, offset, length } = operation
|
const { path, offset, length } = operation
|
||||||
const rangeOffset = offset + length
|
const rangeOffset = offset + length
|
||||||
let { document, selection } = state
|
let { document, selection } = state
|
||||||
const { startKey, endKey, startOffset, endOffset } = selection
|
const { anchorKey, focusKey, anchorOffset, focusOffset } = selection
|
||||||
let node = document.assertPath(path)
|
let node = document.assertPath(path)
|
||||||
|
|
||||||
// Update the selection
|
// Update the selection
|
||||||
if (startKey == node.key && startOffset >= rangeOffset) {
|
if (anchorKey == node.key && anchorOffset >= rangeOffset) {
|
||||||
selection = selection.moveStartOffset(-length)
|
selection = selection.moveAnchorOffset(-length)
|
||||||
}
|
}
|
||||||
if (endKey == node.key && endOffset >= rangeOffset) {
|
if (focusKey == node.key && focusOffset >= rangeOffset) {
|
||||||
selection = selection.moveEndOffset(-length)
|
selection = selection.moveFocusOffset(-length)
|
||||||
}
|
}
|
||||||
|
|
||||||
node = node.removeText(offset, length)
|
node = node.removeText(offset, length)
|
||||||
|
@@ -466,12 +466,18 @@ export function wrapText(transform, prefix, suffix = prefix) {
|
|||||||
const { selection } = state
|
const { selection } = state
|
||||||
transform.wrapTextAtRange(selection, prefix, suffix)
|
transform.wrapTextAtRange(selection, prefix, suffix)
|
||||||
|
|
||||||
// Adding the suffix will have pushed the end of the selection further on, so
|
|
||||||
// we need to move it back to account for this.
|
|
||||||
transform.moveEndOffset(0 - suffix.length)
|
|
||||||
|
|
||||||
// If the selection was collapsed, it will have moved the start offset too.
|
// If the selection was collapsed, it will have moved the start offset too.
|
||||||
if (selection.isCollapsed) {
|
if (selection.isCollapsed) {
|
||||||
transform.moveStartOffset(0 - prefix.length)
|
transform.moveStartOffset(0 - prefix.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adding the suffix will have pushed the end of the selection further on, so
|
||||||
|
// we need to move it back to account for this.
|
||||||
|
transform.moveEndOffset(0 - suffix.length)
|
||||||
|
|
||||||
|
// There's a chance that the selection points moved "through" each other,
|
||||||
|
// resulting in a now-incorrect selection direction.
|
||||||
|
if (selection.isForward != transform.state.selection.isForward) {
|
||||||
|
transform.flipSelection()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -144,6 +144,7 @@ import {
|
|||||||
extendForward,
|
extendForward,
|
||||||
extendToEndOf,
|
extendToEndOf,
|
||||||
extendToStartOf,
|
extendToStartOf,
|
||||||
|
flipSelection,
|
||||||
focus,
|
focus,
|
||||||
moveBackward,
|
moveBackward,
|
||||||
moveForward,
|
moveForward,
|
||||||
@@ -321,6 +322,7 @@ export default {
|
|||||||
extendToEndOf,
|
extendToEndOf,
|
||||||
extendToStartOf,
|
extendToStartOf,
|
||||||
focus,
|
focus,
|
||||||
|
flipSelection,
|
||||||
moveBackward,
|
moveBackward,
|
||||||
moveForward,
|
moveForward,
|
||||||
moveEndOffset,
|
moveEndOffset,
|
||||||
|
@@ -22,6 +22,8 @@ export const moveToRangeOf = generate('moveToRangeOf')
|
|||||||
export const moveStartOffset = generate('moveStartOffset')
|
export const moveStartOffset = generate('moveStartOffset')
|
||||||
export const moveEndOffset = generate('moveEndOffset')
|
export const moveEndOffset = generate('moveEndOffset')
|
||||||
|
|
||||||
|
export const flipSelection = generate('flip')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move the selection to the end of the next block.
|
* Move the selection to the end of the next block.
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user