1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-21 14:41:23 +02:00

work on refactoring selection transforms

This commit is contained in:
Ian Storm Taylor
2016-08-18 13:33:32 -07:00
parent 24f36862d6
commit 44008d3c31
5 changed files with 185 additions and 167 deletions

View File

@@ -3,14 +3,6 @@ import includes from 'lodash/includes'
import memoize from '../utils/memoize' import memoize from '../utils/memoize'
import { Record } from 'immutable' 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. * 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`. * Move to the start of a `node`.
* *
@@ -435,6 +459,7 @@ class Selection extends new Record(DEFAULTS) {
* *
* @param {Node} start * @param {Node} start
* @param {Node} end (optional) * @param {Node} end (optional)
* @param {Document} document
* @return {Selection} selection * @return {Selection} selection
*/ */
@@ -444,7 +469,7 @@ class Selection extends new Record(DEFAULTS) {
anchorOffset: 0, anchorOffset: 0,
focusKey: end.key, focusKey: end.key,
focusOffset: end.length, focusOffset: end.length,
isBackward: start == end ? false : null isBackward: null,
}) })
} }
@@ -485,11 +510,15 @@ class Selection extends new Record(DEFAULTS) {
*/ */
moveToOffsets(anchor, focus = anchor) { moveToOffsets(anchor, focus = anchor) {
return this.merge({ const props = {}
anchorOffset: anchor, props.anchorOffset = anchor
focusOffset: focus, props.focusOffset = focus
isBackward: null
}) 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. * 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 [ p, s ] = pattern.split('%')
const anchor = `${p}Anchor${s}` const anchor = `${p}Anchor${s}`
const edge = `${p}Edge${s}` const edge = `${p}Edge${s}`
@@ -576,8 +605,6 @@ START_END_METHODS.concat(EDGE_METHODS).forEach((pattern) => {
: this[focus](...args) : this[focus](...args)
} }
if (!includes(EDGE_METHODS, pattern)) return
Selection.prototype[edge] = function (...args) { Selection.prototype[edge] = function (...args) {
return this[anchor](...args) || this[focus](...args) return this[anchor](...args) || this[focus](...args)
} }

View File

@@ -64,6 +64,7 @@ class Transform {
const { state } = properties const { state } = properties
this.state = state this.state = state
this.operations = [] this.operations = []
this.transforms = []
} }
/** /**
@@ -263,7 +264,7 @@ class Transform {
Object.keys(Transforms).forEach((type) => { Object.keys(Transforms).forEach((type) => {
Transform.prototype[type] = function (...args) { Transform.prototype[type] = function (...args) {
this.operations.push({ type, args }) this.transforms.push({ type, args })
return Transforms[type](this, ...args) return Transforms[type](this, ...args)
} }
}) })

View File

@@ -620,6 +620,7 @@ export function wrapInline(transform, properties) {
}) })
} }
selection = selection.normalize(document)
state = state.merge({ selection }) state = state.merge({ selection })
transform.state = state transform.state = state
return transform return transform

View File

@@ -1,4 +1,5 @@
import Normalize from '../utils/normalize'
import Selection from '../models/selection' import Selection from '../models/selection'
/** /**
@@ -9,61 +10,53 @@ import Selection from '../models/selection'
*/ */
export function blur(transform) { export function blur(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { selection } = state
selection = selection.blur() const sel = selection.blur()
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
* Move the focus point to the anchor point. * Move the focus point to the anchor point.
* *
* @param {Transform} transform
* @return {Transform} * @return {Transform}
*/ */
export function collapseToAnchor(transform) { export function collapseToAnchor(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { selection } = state
selection = selection.collapseToAnchor() const sel = selection.collapseToAnchor()
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
* Move the anchor point to the focus point. * Move the anchor point to the
* * focus point.
* @param {Transform} transform
* @return {Transform} * @return {Transform}
*/ */
export function collapseToFocus(transform) { export function collapseToFocus(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { selection } = state
selection = selection.collapseToFocus() const sel = selection.collapseToFocus()
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
* Move to the end of a `node`. * Move to the end of a `node`.
* *
* @param {Transform} transform
* @param {Node} node
* @return {Transform} * @return {Transform}
*/ */
export function collapseToEndOf(transform, ...args) { export function collapseToEndOf(transform, node) {
let { state } = transform const { state } = transform
let { document, selection } = state const { selection } = state
selection = selection.collapseToEndOf(...args) const sel = selection.collapseToEndOf(node)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -74,20 +67,15 @@ export function collapseToEndOf(transform, ...args) {
*/ */
export function collapseToEndOfNextBlock(transform) { export function collapseToEndOfNextBlock(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { document, selection } = state
let blocks = document.getBlocksAtRange(selection) const blocks = document.getBlocksAtRange(selection)
let block = blocks.last() const last = blocks.last()
if (!block) return transform const next = document.getNextBlock(last)
let next = document.getNextBlock(block)
if (!next) return transform if (!next) return transform
selection = selection.collapseToEndOf(next) const sel = selection.collapseToEndOf(next)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -98,20 +86,15 @@ export function collapseToEndOfNextBlock(transform) {
*/ */
export function collapseToEndOfNextText(transform) { export function collapseToEndOfNextText(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { document, selection } = state
let texts = document.getTextsAtRange(selection) const texts = document.getTextsAtRange(selection)
let text = texts.last() const last = texts.last()
if (!text) return transform const next = document.getNextText(last)
let next = document.getNextText(text)
if (!next) return transform if (!next) return transform
selection = selection.collapseToEndOf(next) const sel = selection.collapseToEndOf(next)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -122,20 +105,15 @@ export function collapseToEndOfNextText(transform) {
*/ */
export function collapseToEndOfPreviousBlock(transform) { export function collapseToEndOfPreviousBlock(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { document, selection } = state
let blocks = document.getBlocksAtRange(selection) const blocks = document.getBlocksAtRange(selection)
let block = blocks.first() const first = blocks.first()
if (!block) return transform const previous = document.getPreviousBlock(first)
let previous = document.getPreviousBlock(block)
if (!previous) return transform if (!previous) return transform
selection = selection.collapseToEndOf(previous) const sel = selection.collapseToEndOf(previous)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -146,36 +124,29 @@ export function collapseToEndOfPreviousBlock(transform) {
*/ */
export function collapseToEndOfPreviousText(transform) { export function collapseToEndOfPreviousText(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { document, selection } = state
let texts = document.getTextsAtRange(selection) const texts = document.getTextsAtRange(selection)
let text = texts.first() const first = texts.first()
if (!text) return transform const previous = document.getPreviousText(first)
let previous = document.getPreviousText(text)
if (!previous) return transform if (!previous) return transform
selection = selection.collapseToEndOf(previous) const sel = selection.collapseToEndOf(previous)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
* Move to the start of a `node`. * Move to the start of a `node
* * `.
* @param {Transform} transform
* @return {Transform} * @return {Transform}
*/ */
export function collapseToStartOf(transform, node) { export function collapseToStartOf(transform, node) {
let { state } = transform const { state } = transform
let { document, selection } = state const { selection } = state
selection = selection.collapseToStartOf(node) const sel = selection.collapseToStartOf(node)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -186,20 +157,15 @@ export function collapseToStartOf(transform, node) {
*/ */
export function collapseToStartOfNextBlock(transform) { export function collapseToStartOfNextBlock(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { document, selection } = state
let blocks = document.getBlocksAtRange(selection) const blocks = document.getBlocksAtRange(selection)
let block = blocks.last() const last = blocks.last()
if (!block) return transform const next = document.getNextBlock(last)
let next = document.getNextBlock(block)
if (!next) return transform if (!next) return transform
selection = selection.collapseToStartOf(next) const sel = selection.collapseToStartOf(next)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -210,20 +176,15 @@ export function collapseToStartOfNextBlock(transform) {
*/ */
export function collapseToStartOfNextText(transform) { export function collapseToStartOfNextText(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { document, selection } = state
let texts = document.getTextsAtRange(selection) const texts = document.getTextsAtRange(selection)
let text = texts.last() const last = texts.last()
if (!text) return transform const next = document.getNextText(last)
let next = document.getNextText(text)
if (!next) return transform if (!next) return transform
selection = selection.collapseToStartOf(next) const sel = selection.collapseToStartOf(next)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -234,20 +195,15 @@ export function collapseToStartOfNextText(transform) {
*/ */
export function collapseToStartOfPreviousBlock(transform) { export function collapseToStartOfPreviousBlock(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { document, selection } = state
let blocks = document.getBlocksAtRange(selection) const blocks = document.getBlocksAtRange(selection)
let block = blocks.first() const first = blocks.first()
if (!block) return transform const previous = document.getPreviousBlock(first)
let previous = document.getPreviousBlock(block)
if (!previous) return transform if (!previous) return transform
selection = selection.collapseToStartOf(previous) const sel = selection.collapseToStartOf(previous)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -258,20 +214,15 @@ export function collapseToStartOfPreviousBlock(transform) {
*/ */
export function collapseToStartOfPreviousText(transform) { export function collapseToStartOfPreviousText(transform) {
let { state } = transform const { state } = transform
let { document, selection } = state const { document, selection } = state
let texts = document.getTextsAtRange(selection) const texts = document.getTextsAtRange(selection)
let text = texts.first() const first = texts.first()
if (!text) return transform const previous = document.getPreviousText(first)
let previous = document.getPreviousText(text)
if (!previous) return transform if (!previous) return transform
selection = selection.collapseToStartOf(previous) const sel = selection.collapseToStartOf(previous)
selection = selection.normalize(document) return transform.updateSelection(sel)
state = state.merge({ selection })
transform.state = state
return transform
} }
/** /**
@@ -345,6 +296,7 @@ export function extendToStartOf(transform, ...args) {
/** /**
* Focus the selection. * Focus the selection.
* *
* @param {Transform} transform
* @return {Transform} * @return {Transform}
*/ */
@@ -462,3 +414,25 @@ export function moveToRangeOf(transform, ...args) {
transform.state = state transform.state = state
return transform 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
})
}

View File

@@ -16,9 +16,8 @@ import typeOf from 'type-of'
function block(value) { function block(value) {
if (value instanceof Block) return value if (value instanceof Block) return value
const type = typeOf(value)
switch (type) { switch (typeOf(value)) {
case 'string': case 'string':
case 'object': { case 'object': {
return Block.create(nodeProperties(value)) return Block.create(nodeProperties(value))
@@ -38,9 +37,8 @@ function block(value) {
function inline(value) { function inline(value) {
if (value instanceof Inline) return value if (value instanceof Inline) return value
const type = typeOf(value)
switch (type) { switch (typeOf(value)) {
case 'string': case 'string':
case 'object': { case 'object': {
return Inline.create(nodeProperties(value)) return Inline.create(nodeProperties(value))
@@ -64,8 +62,7 @@ function key(value) {
if (value instanceof Inline) return value.key if (value instanceof Inline) return value.key
if (value instanceof Text) return value.key if (value instanceof Text) return value.key
const type = typeOf(value) if (typeOf(value) == 'string') return value
if (type == '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}".`) 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`. * Normalize a mark argument `value`.
* *
* @param {Mark || String || Object} mark * @param {Mark || String || Object} value
* @return {Mark} * @return {Mark}
*/ */
function mark(value) { function mark(value) {
if (value instanceof Mark) return value if (value instanceof Mark) return value
const type = typeOf(value)
switch (type) { switch (typeOf(value)) {
case 'string': case 'string':
case 'object': { case 'object': {
return Mark.create(markProperties(value)) return Mark.create(markProperties(value))
@@ -101,9 +97,8 @@ function mark(value) {
function markProperties(value = {}) { function markProperties(value = {}) {
const ret = {} const ret = {}
const type = typeOf(value)
switch (type) { switch (typeOf(value)) {
case 'string': { case 'string': {
ret.type = value ret.type = value
break break
@@ -135,9 +130,8 @@ function markProperties(value = {}) {
function nodeProperties(value = {}) { function nodeProperties(value = {}) {
const ret = {} const ret = {}
const type = typeOf(value)
switch (type) { switch (typeOf(value)) {
case 'string': { case 'string': {
ret.type = value ret.type = value
break break
@@ -161,6 +155,26 @@ function nodeProperties(value = {}) {
return ret 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. * Export.
* *
@@ -174,5 +188,6 @@ export default {
mark, mark,
markProperties, markProperties,
nodeProperties, nodeProperties,
selection,
} }