1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-21 22:45:18 +02:00

refactor for operations

This commit is contained in:
Ian Storm Taylor
2016-08-16 20:06:02 -07:00
parent 9ae245ddab
commit 6af9466c60
4 changed files with 194 additions and 26 deletions

View File

@@ -42,6 +42,20 @@ class Character extends CharacterRecord {
return new List(array.map(Character.create)) return new List(array.map(Character.create))
} }
/**
* Create a characters list from a `string` and optional `marks`.
*
* @param {String} string
* @param {Set} marks (optional)
* @return {List}
*/
static createListFromText(string, marks) {
const chars = string.split('').map(text => { return { text, marks } })
const list = Character.createList(chars)
return list
}
/** /**
* Get the kind. * Get the kind.
* *

View File

@@ -60,6 +60,23 @@ const Node = {
return descendant return descendant
}, },
/**
* Assert that a node exists at `path` and return it.
*
* @param {Array} path
* @return {Node}
*/
assertPath(path) {
const descendant = this.getDescendantAtPath(path)
if (!descendant) {
throw new Error(`Could not find a descendant at path "${path}".`)
}
return descendant
},
/** /**
* Concat children `nodes` on to the end of the node. * Concat children `nodes` on to the end of the node.
* *
@@ -405,6 +422,24 @@ const Node = {
return child return child
}, },
/**
* Get a descendant by `path`.
*
* @param {Array} path
* @return {Node || Void}
*/
getDescedantAtPath(path) {
let descendant = this
for (const index of path) {
if (!descendant.nodes) return
descendant = descendant.nodes.get(index)
}
return descendant
},
/** /**
* Get the depth of a child node by `key`, with optional `startAt`. * Get the depth of a child node by `key`, with optional `startAt`.
* *
@@ -721,6 +756,27 @@ const Node = {
return node return node
}, },
/**
* Get the path of a descendant node by `key`.
*
* @param {String || Node} node
* @return {Array}
*/
getPath(key) {
let child = this.assertDescendant(key)
let path = []
let parent
while (parent = this.getParent(child)) {
const index = parent.nodes.indexOf(child)
path.push(index)
child = parent
}
return path
},
/** /**
* Get the node before a descendant node by `key`. * Get the node before a descendant node by `key`.
* *
@@ -911,6 +967,19 @@ const Node = {
return this.merge({ nodes }) return this.merge({ nodes })
}, },
/**
* Insert a `node` at `index`.
*
* @param {Number} index
* @param {Node} node
* @return {Node}
*/
insertNode(index, node) {
const nodes = this.nodes.splice(index, 0, node)
return this.merge({ nodes })
},
/** /**
* Check if the inline nodes are split at a `range`. * Check if the inline nodes are split at a `range`.
* *
@@ -1106,6 +1175,18 @@ const Node = {
return node return node
}, },
/**
* Remove a node at `index`.
*
* @param {Number} index
* @return {Node}
*/
removeNode(index) {
const nodes = this.nodes.splice(index, 1)
return this.merge({ nodes })
},
/** /**
* Set a new value for a child node by `key`. * Set a new value for a child node by `key`.
* *

View File

@@ -98,6 +98,28 @@ class Text extends new Record(DEFAULTS) {
.join('') .join('')
} }
/**
* Add a `mark` at `index` and `length`.
*
* @param {Number} index
* @param {Number} length
* @param {Mark} mark
* @return {Text}
*/
addMark(index, length, mark) {
const characters = this.characters.map((char, i) => {
if (i < index) return char
if (i > index + length) return char
let { marks } = char
marks = marks.add(mark)
char = char.merge({ marks })
return char
})
return this.merge({ characters })
}
/** /**
* Derive a set of decorated characters with `decorators`. * Derive a set of decorated characters with `decorators`.
* *
@@ -129,6 +151,21 @@ class Text extends new Record(DEFAULTS) {
return schema.__getDecorators(this) return schema.__getDecorators(this)
} }
/**
* Get the marks on the text at `index`.
*
* @param {Number} index
* @return {Set}
*/
getMarksAtIndex(index) {
if (index == 0) return Mark.createSet()
const { characters } = this
const char = characters.get(index - 1)
if (!char) return Mark.createSet()
return char.marks
}
/** /**
* Derive the ranges for a list of `characters`. * Derive the ranges for a list of `characters`.
* *
@@ -181,50 +218,86 @@ class Text extends new Record(DEFAULTS) {
} }
/** /**
* Remove characters from the text node from `start` to `end`. * Insert `text` at `index`.
* *
* @param {Number} start * @param {Numbder} index
* @param {Number} end * @param {String} text
* @param {String} marks (optional)
* @return {Text} text * @return {Text} text
*/ */
removeCharacters(start, end) { insertText(index, text, marks) {
marks = marks || this.getMarksAtIndex(index)
let { characters } = this let { characters } = this
const chars = Character.createListFromText(text, marks)
characters = characters.filterNot((char, i) => { characters = characters.slice(0, index)
return start <= i && i < end .concat(chars)
.concat(characters.slice(index))
return this.merge({ characters })
}
/**
* Remove a `mark` at `index` and `length`.
*
* @param {Number} index
* @param {Number} length
* @param {Mark} mark
* @return {Text}
*/
removeMark(index, length, mark) {
const characters = this.characters.map((char, i) => {
if (i < index) return char
if (i > index + length) return char
let { marks } = char
marks = marks.remove(mark)
char = char.merge({ marks })
return char
}) })
return this.merge({ characters }) return this.merge({ characters })
} }
/** /**
* Insert text `string` at `index`. * Remove text from the text node at `index` for `length`.
* *
* @param {Numbder} index * @param {Number} index
* @param {String} string * @param {Number} length
* @param {String} marks (optional)
* @return {Text} text * @return {Text} text
*/ */
insertText(index, string, marks) { removeText(index, length) {
let { characters } = this let { characters } = this
let start = index
if (!marks) { let end = index + length
const prev = index ? characters.get(index - 1) : null characters = characters.filterNot((char, i) => start <= i && i < end)
marks = prev ? prev.marks : Mark.createSet() return this.merge({ characters })
} }
const chars = Character.createList(string.split('').map((char) => { /**
return { * Update a `mark` at `index` and `length` with `properties`.
text: char, *
marks * @param {Number} index
} * @param {Number} length
})) * @param {Mark} mark
* @param {Object} properties
* @return {Text}
*/
characters = characters.slice(0, index) updateMark(index, length, mark, properties) {
.concat(chars) const characters = this.characters.map((char, i) => {
.concat(characters.slice(index)) if (i < index) return char
if (i > index + length) return char
let { marks } = char
const j = marks.indexOf(mark)
let m = marks.get(j)
m = m.merge(properties)
marks = marks.set(j, m)
char = char.merge({ marks })
return char
})
return this.merge({ characters }) return this.merge({ characters })
} }

View File

@@ -77,7 +77,7 @@ export function deleteAtRange(transform, range) {
// If the start and end nodes are the same, just remove characters. // If the start and end nodes are the same, just remove characters.
if (startKey == endKey) { if (startKey == endKey) {
let text = document.getDescendant(startKey) let text = document.getDescendant(startKey)
text = text.removeCharacters(startOffset, endOffset) text = text.removeText(startOffset, endOffset - startOffset)
document = document.updateDescendant(text) document = document.updateDescendant(text)
document = document.normalize() document = document.normalize()
state = state.merge({ document }) state = state.merge({ document })