mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-21 06:31:28 +02:00
work on refactoring selection transforms
This commit is contained in:
@@ -3,14 +3,6 @@ import includes from 'lodash/includes'
|
||||
import memoize from '../utils/memoize'
|
||||
import { Record } from 'immutable'
|
||||
|
||||
/**
|
||||
* Start-and-end convenience methods to auto-generate.
|
||||
*/
|
||||
|
||||
const START_END_METHODS = [
|
||||
'collapseTo%'
|
||||
]
|
||||
|
||||
/**
|
||||
* Start-end-and-edge convenience methods to auto-generate.
|
||||
*/
|
||||
@@ -398,6 +390,38 @@ class Selection extends new Record(DEFAULTS) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the end point to the start point.
|
||||
*
|
||||
* @return {Selection} 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} 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`.
|
||||
*
|
||||
@@ -435,6 +459,7 @@ class Selection extends new Record(DEFAULTS) {
|
||||
*
|
||||
* @param {Node} start
|
||||
* @param {Node} end (optional)
|
||||
* @param {Document} document
|
||||
* @return {Selection} selection
|
||||
*/
|
||||
|
||||
@@ -444,7 +469,7 @@ class Selection extends new Record(DEFAULTS) {
|
||||
anchorOffset: 0,
|
||||
focusKey: end.key,
|
||||
focusOffset: end.length,
|
||||
isBackward: start == end ? false : null
|
||||
isBackward: null,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -485,11 +510,15 @@ class Selection extends new Record(DEFAULTS) {
|
||||
*/
|
||||
|
||||
moveToOffsets(anchor, focus = anchor) {
|
||||
return this.merge({
|
||||
anchorOffset: anchor,
|
||||
focusOffset: focus,
|
||||
isBackward: null
|
||||
})
|
||||
const props = {}
|
||||
props.anchorOffset = anchor
|
||||
props.focusOffset = focus
|
||||
|
||||
if (this.anchorKey == this.focusKey) {
|
||||
props.isBackward = anchor > focus
|
||||
}
|
||||
|
||||
return this.merge(props)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,7 +585,7 @@ class Selection extends new Record(DEFAULTS) {
|
||||
* Add start, end and edge convenience methods.
|
||||
*/
|
||||
|
||||
START_END_METHODS.concat(EDGE_METHODS).forEach((pattern) => {
|
||||
EDGE_METHODS.forEach((pattern) => {
|
||||
const [ p, s ] = pattern.split('%')
|
||||
const anchor = `${p}Anchor${s}`
|
||||
const edge = `${p}Edge${s}`
|
||||
@@ -576,8 +605,6 @@ START_END_METHODS.concat(EDGE_METHODS).forEach((pattern) => {
|
||||
: this[focus](...args)
|
||||
}
|
||||
|
||||
if (!includes(EDGE_METHODS, pattern)) return
|
||||
|
||||
Selection.prototype[edge] = function (...args) {
|
||||
return this[anchor](...args) || this[focus](...args)
|
||||
}
|
||||
|
@@ -64,6 +64,7 @@ class Transform {
|
||||
const { state } = properties
|
||||
this.state = state
|
||||
this.operations = []
|
||||
this.transforms = []
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,7 +264,7 @@ class Transform {
|
||||
|
||||
Object.keys(Transforms).forEach((type) => {
|
||||
Transform.prototype[type] = function (...args) {
|
||||
this.operations.push({ type, args })
|
||||
this.transforms.push({ type, args })
|
||||
return Transforms[type](this, ...args)
|
||||
}
|
||||
})
|
||||
|
@@ -620,6 +620,7 @@ export function wrapInline(transform, properties) {
|
||||
})
|
||||
}
|
||||
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
|
@@ -1,4 +1,5 @@
|
||||
|
||||
import Normalize from '../utils/normalize'
|
||||
import Selection from '../models/selection'
|
||||
|
||||
/**
|
||||
@@ -9,61 +10,53 @@ import Selection from '../models/selection'
|
||||
*/
|
||||
|
||||
export function blur(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.blur()
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
const sel = selection.blur()
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the focus point to the anchor point.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function collapseToAnchor(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.collapseToAnchor()
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
const sel = selection.collapseToAnchor()
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the anchor point to the focus point.
|
||||
*
|
||||
* Move the anchor point to the
|
||||
* focus point.
|
||||
* @param {Transform} transform
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function collapseToFocus(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.collapseToFocus()
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
const sel = selection.collapseToFocus()
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to the end of a `node`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {Node} node
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function collapseToEndOf(transform, ...args) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.collapseToEndOf(...args)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
export function collapseToEndOf(transform, node) {
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
const sel = selection.collapseToEndOf(node)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,20 +67,15 @@ export function collapseToEndOf(transform, ...args) {
|
||||
*/
|
||||
|
||||
export function collapseToEndOfNextBlock(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let blocks = document.getBlocksAtRange(selection)
|
||||
let block = blocks.last()
|
||||
if (!block) return transform
|
||||
|
||||
let next = document.getNextBlock(block)
|
||||
const { state } = transform
|
||||
const { document, selection } = state
|
||||
const blocks = document.getBlocksAtRange(selection)
|
||||
const last = blocks.last()
|
||||
const next = document.getNextBlock(last)
|
||||
if (!next) return transform
|
||||
|
||||
selection = selection.collapseToEndOf(next)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const sel = selection.collapseToEndOf(next)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,20 +86,15 @@ export function collapseToEndOfNextBlock(transform) {
|
||||
*/
|
||||
|
||||
export function collapseToEndOfNextText(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let texts = document.getTextsAtRange(selection)
|
||||
let text = texts.last()
|
||||
if (!text) return transform
|
||||
|
||||
let next = document.getNextText(text)
|
||||
const { state } = transform
|
||||
const { document, selection } = state
|
||||
const texts = document.getTextsAtRange(selection)
|
||||
const last = texts.last()
|
||||
const next = document.getNextText(last)
|
||||
if (!next) return transform
|
||||
|
||||
selection = selection.collapseToEndOf(next)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const sel = selection.collapseToEndOf(next)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,20 +105,15 @@ export function collapseToEndOfNextText(transform) {
|
||||
*/
|
||||
|
||||
export function collapseToEndOfPreviousBlock(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let blocks = document.getBlocksAtRange(selection)
|
||||
let block = blocks.first()
|
||||
if (!block) return transform
|
||||
|
||||
let previous = document.getPreviousBlock(block)
|
||||
const { state } = transform
|
||||
const { document, selection } = state
|
||||
const blocks = document.getBlocksAtRange(selection)
|
||||
const first = blocks.first()
|
||||
const previous = document.getPreviousBlock(first)
|
||||
if (!previous) return transform
|
||||
|
||||
selection = selection.collapseToEndOf(previous)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const sel = selection.collapseToEndOf(previous)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,36 +124,29 @@ export function collapseToEndOfPreviousBlock(transform) {
|
||||
*/
|
||||
|
||||
export function collapseToEndOfPreviousText(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let texts = document.getTextsAtRange(selection)
|
||||
let text = texts.first()
|
||||
if (!text) return transform
|
||||
|
||||
let previous = document.getPreviousText(text)
|
||||
const { state } = transform
|
||||
const { document, selection } = state
|
||||
const texts = document.getTextsAtRange(selection)
|
||||
const first = texts.first()
|
||||
const previous = document.getPreviousText(first)
|
||||
if (!previous) return transform
|
||||
|
||||
selection = selection.collapseToEndOf(previous)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const sel = selection.collapseToEndOf(previous)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to the start of a `node`.
|
||||
*
|
||||
* Move to the start of a `node
|
||||
* `.
|
||||
* @param {Transform} transform
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function collapseToStartOf(transform, node) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
selection = selection.collapseToStartOf(node)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const { state } = transform
|
||||
const { selection } = state
|
||||
const sel = selection.collapseToStartOf(node)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,20 +157,15 @@ export function collapseToStartOf(transform, node) {
|
||||
*/
|
||||
|
||||
export function collapseToStartOfNextBlock(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let blocks = document.getBlocksAtRange(selection)
|
||||
let block = blocks.last()
|
||||
if (!block) return transform
|
||||
|
||||
let next = document.getNextBlock(block)
|
||||
const { state } = transform
|
||||
const { document, selection } = state
|
||||
const blocks = document.getBlocksAtRange(selection)
|
||||
const last = blocks.last()
|
||||
const next = document.getNextBlock(last)
|
||||
if (!next) return transform
|
||||
|
||||
selection = selection.collapseToStartOf(next)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const sel = selection.collapseToStartOf(next)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,20 +176,15 @@ export function collapseToStartOfNextBlock(transform) {
|
||||
*/
|
||||
|
||||
export function collapseToStartOfNextText(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let texts = document.getTextsAtRange(selection)
|
||||
let text = texts.last()
|
||||
if (!text) return transform
|
||||
|
||||
let next = document.getNextText(text)
|
||||
const { state } = transform
|
||||
const { document, selection } = state
|
||||
const texts = document.getTextsAtRange(selection)
|
||||
const last = texts.last()
|
||||
const next = document.getNextText(last)
|
||||
if (!next) return transform
|
||||
|
||||
selection = selection.collapseToStartOf(next)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const sel = selection.collapseToStartOf(next)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,20 +195,15 @@ export function collapseToStartOfNextText(transform) {
|
||||
*/
|
||||
|
||||
export function collapseToStartOfPreviousBlock(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let blocks = document.getBlocksAtRange(selection)
|
||||
let block = blocks.first()
|
||||
if (!block) return transform
|
||||
|
||||
let previous = document.getPreviousBlock(block)
|
||||
const { state } = transform
|
||||
const { document, selection } = state
|
||||
const blocks = document.getBlocksAtRange(selection)
|
||||
const first = blocks.first()
|
||||
const previous = document.getPreviousBlock(first)
|
||||
if (!previous) return transform
|
||||
|
||||
selection = selection.collapseToStartOf(previous)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const sel = selection.collapseToStartOf(previous)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,20 +214,15 @@ export function collapseToStartOfPreviousBlock(transform) {
|
||||
*/
|
||||
|
||||
export function collapseToStartOfPreviousText(transform) {
|
||||
let { state } = transform
|
||||
let { document, selection } = state
|
||||
let texts = document.getTextsAtRange(selection)
|
||||
let text = texts.first()
|
||||
if (!text) return transform
|
||||
|
||||
let previous = document.getPreviousText(text)
|
||||
const { state } = transform
|
||||
const { document, selection } = state
|
||||
const texts = document.getTextsAtRange(selection)
|
||||
const first = texts.first()
|
||||
const previous = document.getPreviousText(first)
|
||||
if (!previous) return transform
|
||||
|
||||
selection = selection.collapseToStartOf(previous)
|
||||
selection = selection.normalize(document)
|
||||
state = state.merge({ selection })
|
||||
transform.state = state
|
||||
return transform
|
||||
const sel = selection.collapseToStartOf(previous)
|
||||
return transform.updateSelection(sel)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,6 +296,7 @@ export function extendToStartOf(transform, ...args) {
|
||||
/**
|
||||
* Focus the selection.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
@@ -462,3 +414,25 @@ export function moveToRangeOf(transform, ...args) {
|
||||
transform.state = state
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the selection with a new `selection`.
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {Mixed} sel
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function updateSelection(transform, sel) {
|
||||
sel = Normalize.selection(sel)
|
||||
|
||||
let { state } = transform
|
||||
let { selection } = state
|
||||
selection = selection.merge(sel)
|
||||
state = state.merge({ selection })
|
||||
|
||||
transform.add(state, {
|
||||
type: 'update-selection',
|
||||
selection: sel
|
||||
})
|
||||
}
|
||||
|
@@ -16,9 +16,8 @@ import typeOf from 'type-of'
|
||||
|
||||
function block(value) {
|
||||
if (value instanceof Block) return value
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
switch (typeOf(value)) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Block.create(nodeProperties(value))
|
||||
@@ -38,9 +37,8 @@ function block(value) {
|
||||
|
||||
function inline(value) {
|
||||
if (value instanceof Inline) return value
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
switch (typeOf(value)) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Inline.create(nodeProperties(value))
|
||||
@@ -64,8 +62,7 @@ function key(value) {
|
||||
if (value instanceof Inline) return value.key
|
||||
if (value instanceof Text) return value.key
|
||||
|
||||
const type = typeOf(value)
|
||||
if (type == 'string') return value
|
||||
if (typeOf(value) == 'string') return value
|
||||
|
||||
throw new Error(`Invalid \`key\` argument! It must be either a block, an inline, a text, or a string. You passed: "${value}".`)
|
||||
}
|
||||
@@ -73,15 +70,14 @@ function key(value) {
|
||||
/**
|
||||
* Normalize a mark argument `value`.
|
||||
*
|
||||
* @param {Mark || String || Object} mark
|
||||
* @param {Mark || String || Object} value
|
||||
* @return {Mark}
|
||||
*/
|
||||
|
||||
function mark(value) {
|
||||
if (value instanceof Mark) return value
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
switch (typeOf(value)) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Mark.create(markProperties(value))
|
||||
@@ -101,9 +97,8 @@ function mark(value) {
|
||||
|
||||
function markProperties(value = {}) {
|
||||
const ret = {}
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
switch (typeOf(value)) {
|
||||
case 'string': {
|
||||
ret.type = value
|
||||
break
|
||||
@@ -135,9 +130,8 @@ function markProperties(value = {}) {
|
||||
|
||||
function nodeProperties(value = {}) {
|
||||
const ret = {}
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
switch (typeOf(value)) {
|
||||
case 'string': {
|
||||
ret.type = value
|
||||
break
|
||||
@@ -161,6 +155,26 @@ function nodeProperties(value = {}) {
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a selection argument `value`.
|
||||
*
|
||||
* @param {Selection || Object} value
|
||||
* @return {Selection}
|
||||
*/
|
||||
|
||||
function selection(value) {
|
||||
if (value instanceof Selection) return value
|
||||
|
||||
switch (typeOf(value)) {
|
||||
case 'object': {
|
||||
return Selection.create(value)
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid \`selection\` argument! It must be a selection or an object. You passed: "${value}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*
|
||||
@@ -174,5 +188,6 @@ export default {
|
||||
mark,
|
||||
markProperties,
|
||||
nodeProperties,
|
||||
selection,
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user