mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-11 09:43:58 +02:00
cleanup
This commit is contained in:
45
Makefile
45
Makefile
@@ -24,28 +24,51 @@ clean:
|
||||
|
||||
# Build the source.
|
||||
dist: $(shell find ./lib)
|
||||
@ $(babel) --out-dir ./dist ./lib
|
||||
@ $(babel) \
|
||||
--out-dir \
|
||||
./dist \
|
||||
./lib
|
||||
@ touch ./dist
|
||||
|
||||
# Build the auto-markdown example.
|
||||
example-auto-markdown:
|
||||
@ $(browserify) --debug --transform babelify --outfile ./examples/auto-markdown/build.js ./examples/auto-markdown/index.js
|
||||
@ $(browserify) \
|
||||
--debug \
|
||||
--transform babelify \
|
||||
--outfile ./examples/auto-markdown/build.js \
|
||||
./examples/auto-markdown/index.js
|
||||
|
||||
# Build the links example.
|
||||
example-links:
|
||||
@ $(browserify) --debug --transform babelify --outfile ./examples/links/build.js ./examples/links/index.js
|
||||
@ $(browserify) \
|
||||
--debug \
|
||||
--transform babelify \
|
||||
--outfile ./examples/links/build.js \
|
||||
./examples/links/index.js
|
||||
|
||||
# Build the plain-text example.
|
||||
example-plain-text:
|
||||
@ $(browserify) --debug --transform babelify --outfile ./examples/plain-text/build.js ./examples/plain-text/index.js
|
||||
@ $(browserify) \
|
||||
--debug \
|
||||
--transform babelify \
|
||||
--outfile ./examples/plain-text/build.js \
|
||||
./examples/plain-text/index.js
|
||||
|
||||
# Build the rich-text example.
|
||||
example-rich-text:
|
||||
@ $(browserify) --debug --transform babelify --outfile ./examples/rich-text/build.js ./examples/rich-text/index.js
|
||||
@ $(browserify) \
|
||||
--debug \
|
||||
--transform babelify \
|
||||
--outfile ./examples/rich-text/build.js \
|
||||
./examples/rich-text/index.js
|
||||
|
||||
# Build the table example.
|
||||
example-table:
|
||||
@ $(browserify) --debug --transform babelify --outfile ./examples/table/build.js ./examples/table/index.js
|
||||
@ $(browserify) \
|
||||
--debug \
|
||||
--transform babelify \
|
||||
--outfile ./examples/table/build.js \
|
||||
./examples/table/index.js
|
||||
|
||||
# Install the dependencies.
|
||||
install:
|
||||
@@ -57,14 +80,20 @@ lint:
|
||||
|
||||
# Build the test source.
|
||||
test/browser/support/build.js: $(shell find ./lib) ./test/browser.js
|
||||
@ $(browserify) --debug --transform babelify --outfile ./test/support/build.js ./test/browser.js
|
||||
@ $(browserify) \
|
||||
--debug \
|
||||
--transform babelify \
|
||||
--outfile ./test/support/build.js ./test/browser.js
|
||||
|
||||
# Run the tests.
|
||||
test: test-browser test-server
|
||||
|
||||
# Run the browser-side tests.
|
||||
test-browser: ./test/support/build.js
|
||||
@ $(mocha-phantomjs) --reporter spec --timeout 5000 ./test/support/browser.html
|
||||
@ $(mocha-phantomjs) \
|
||||
--reporter spec \
|
||||
--timeout 5000 \
|
||||
./test/support/browser.html
|
||||
|
||||
# Run the server-side tests.
|
||||
test-server:
|
||||
|
@@ -83,7 +83,7 @@ class Content extends React.Component {
|
||||
const { anchorNode, anchorOffset, focusNode, focusOffset } = native
|
||||
const anchor = OffsetKey.findPoint(anchorNode, anchorOffset)
|
||||
const focus = OffsetKey.findPoint(focusNode, focusOffset)
|
||||
const edges = document.filterDeep((node) => {
|
||||
const edges = document.filterDescendants((node) => {
|
||||
return node.key == anchor.key || node.key == focus.key
|
||||
})
|
||||
|
||||
|
@@ -22,8 +22,24 @@ const Node = {
|
||||
* @param {String or Node} key
|
||||
*/
|
||||
|
||||
assertHasDeep(key) {
|
||||
if (!this.hasDeep(key)) throw new Error('Could not find that child node.')
|
||||
assertHasChild(key) {
|
||||
key = normalizeKey(key)
|
||||
if (!this.hasChild(key)) {
|
||||
throw new Error(`Could not find a child node with key "${key}".`)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Assert that the node has a descendant by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
*/
|
||||
|
||||
assertHasDescendant(key) {
|
||||
key = normalizeKey(key)
|
||||
if (!this.hasDescendant(key)) {
|
||||
throw new Error(`Could not find a descendant node with key "${key}".`)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -42,10 +58,10 @@ const Node = {
|
||||
|
||||
// Make sure the children exist.
|
||||
const { startKey, startOffset, endKey, endOffset } = range
|
||||
node.assertHasDeep(startKey)
|
||||
node.assertHasDeep(endKey)
|
||||
node.assertHasDescendant(startKey)
|
||||
node.assertHasDescendant(endKey)
|
||||
|
||||
let startNode = node.getDeep(startKey)
|
||||
let startNode = node.getDescendant(startKey)
|
||||
|
||||
// If the start and end nodes are the same, remove the matching characters.
|
||||
if (startKey == endKey) {
|
||||
@@ -81,11 +97,11 @@ const Node = {
|
||||
let endParent = node.getParent(endKey)
|
||||
|
||||
const startGrandestParent = node.nodes.find((child) => {
|
||||
return child == startParent || child.hasDeep(startParent)
|
||||
return child == startParent || child.hasDescendant(startParent)
|
||||
})
|
||||
|
||||
const endGrandestParent = node.nodes.find((child) => {
|
||||
return child == endParent || child.hasDeep(endParent)
|
||||
return child == endParent || child.hasDescendant(endParent)
|
||||
})
|
||||
|
||||
const nodes = node.nodes
|
||||
@@ -103,9 +119,9 @@ const Node = {
|
||||
// Then remove the end parent.
|
||||
let endGrandparent = node.getParent(endParent)
|
||||
if (endGrandparent == node) {
|
||||
node = node.removeDeep(endParent)
|
||||
node = node.removeDescendant(endParent)
|
||||
} else {
|
||||
endGrandparent = endGrandparent.removeDeep(endParent)
|
||||
endGrandparent = endGrandparent.removeDescendant(endParent)
|
||||
node = node.updateDeep(endGrandparent)
|
||||
}
|
||||
|
||||
@@ -133,7 +149,7 @@ const Node = {
|
||||
|
||||
// When at start of a text node, merge forwards into the next text node.
|
||||
const { startKey } = range
|
||||
const startNode = node.getDeep(startKey)
|
||||
const startNode = node.getDescendant(startKey)
|
||||
|
||||
if (range.isAtStartOf(startNode)) {
|
||||
const previous = node.getPreviousText(startNode)
|
||||
@@ -170,7 +186,7 @@ const Node = {
|
||||
|
||||
// When at end of a text node, merge forwards into the next text node.
|
||||
const { startKey } = range
|
||||
const startNode = node.getDeep(startKey)
|
||||
const startNode = node.getDescendant(startKey)
|
||||
|
||||
if (range.isAtEndOf(startNode)) {
|
||||
const next = node.getNextText(startNode)
|
||||
@@ -188,33 +204,32 @@ const Node = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Recursively find nodes nodes by `iterator`.
|
||||
* Recursively find all ancestor nodes by `iterator`.
|
||||
*
|
||||
* @param {Function} iterator
|
||||
* @return {Node} node
|
||||
*/
|
||||
|
||||
findDeep(iterator) {
|
||||
const shallow = this.nodes.find(iterator)
|
||||
if (shallow != null) return shallow
|
||||
|
||||
return this.nodes
|
||||
.map(node => node.kind == 'text' ? null : node.findDeep(iterator))
|
||||
.filter(node => node)
|
||||
.first()
|
||||
findDescendant(iterator) {
|
||||
return (
|
||||
this.nodes.find(iterator) ||
|
||||
this.nodes
|
||||
.map(node => node.kind == 'text' ? null : node.findDescendant(iterator))
|
||||
.find(exists => exists)
|
||||
)
|
||||
},
|
||||
|
||||
/**
|
||||
* Recursively filter nodes nodes with `iterator`.
|
||||
* Recursively filter all ancestor nodes with `iterator`.
|
||||
*
|
||||
* @param {Function} iterator
|
||||
* @return {OrderedMap} matches
|
||||
* @return {List} nodes
|
||||
*/
|
||||
|
||||
filterDeep(iterator) {
|
||||
filterDescendants(iterator) {
|
||||
return this.nodes.reduce((matches, child, i, nodes) => {
|
||||
if (iterator(child, i, nodes)) matches = matches.push(child)
|
||||
if (child.kind != 'text') matches = matches.concat(child.filterDeep(iterator))
|
||||
if (child.kind != 'text') matches = matches.concat(child.filterDescendants(iterator))
|
||||
return matches
|
||||
}, Block.createList())
|
||||
},
|
||||
@@ -223,14 +238,14 @@ const Node = {
|
||||
* Get the closest block nodes for each text node in a `range`.
|
||||
*
|
||||
* @param {Selection} range
|
||||
* @return {OrderedMap} nodes
|
||||
* @return {List} nodes
|
||||
*/
|
||||
|
||||
getBlocksAtRange(range) {
|
||||
range = range.normalize(this)
|
||||
const texts = this.getTextsAtRange(range)
|
||||
const blocks = texts.map(text => this.getClosestBlock(text))
|
||||
return blocks
|
||||
return this
|
||||
.getTextsAtRange(range)
|
||||
.map(text => this.getClosestBlock(text))
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -242,16 +257,12 @@ const Node = {
|
||||
|
||||
getCharactersAtRange(range) {
|
||||
range = range.normalize(this)
|
||||
const texts = this.getTextsAtRange(range)
|
||||
let list = new List()
|
||||
|
||||
texts.forEach((text) => {
|
||||
let { characters } = text
|
||||
characters = characters.filter((char, i) => isInRange(i, text, range))
|
||||
list = list.concat(characters)
|
||||
})
|
||||
|
||||
return list
|
||||
return this
|
||||
.getTextsAtRange(range)
|
||||
.reduce((characters, text) => {
|
||||
const chars = text.characters.filter((char, i) => isInRange(i, text, range))
|
||||
return characters.concat(chars)
|
||||
}, Character.createList())
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -259,14 +270,11 @@ const Node = {
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @param {Function} iterator
|
||||
* @return {Node or Null} parent
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getClosest(key, iterator) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
|
||||
let node = this.getDeep(key)
|
||||
let node = this.getDescendant(key)
|
||||
|
||||
while (node = this.getParent(node)) {
|
||||
if (node == this) return null
|
||||
@@ -280,66 +288,46 @@ const Node = {
|
||||
* Get the closest block parent of a `node`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null} parent
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getClosestBlock(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
|
||||
const match = this.getClosest(key, parent => parent.kind == 'block')
|
||||
return match
|
||||
return this.getClosest(key, parent => parent.kind == 'block')
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the closest inline parent of a `node`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null} parent
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getClosestInline(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
|
||||
const match = this.getClosest(key, parent => parent.kind == 'inline')
|
||||
return match
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the furthest inline parent of a node by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null} parent
|
||||
*/
|
||||
|
||||
getFurthestInline(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
|
||||
let child = this.getDeep(key)
|
||||
let furthest = null
|
||||
let next
|
||||
|
||||
while (next = this.getClosestInline(child)) {
|
||||
furthest = next
|
||||
child = next
|
||||
}
|
||||
|
||||
return furthest
|
||||
return this.getClosest(key, parent => parent.kind == 'inline')
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a child node by `key`.
|
||||
*
|
||||
* @param {String} key
|
||||
* @return {Node or Null}
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getDeep(key) {
|
||||
getChild(key) {
|
||||
key = normalizeKey(key)
|
||||
const match = this.findDeep(node => node.key == key)
|
||||
return match || null
|
||||
return this.nodes.find(node => node.key == key)
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a descendant node by `key`.
|
||||
*
|
||||
* @param {String} key
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getDescendant(key) {
|
||||
key = normalizeKey(key)
|
||||
return this.findDescendant(node => node.key == key)
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -352,7 +340,7 @@ const Node = {
|
||||
|
||||
getDepth(key, startAt = 1) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
this.assertHasDescendant(key)
|
||||
|
||||
const shallow = this.nodes.find(node => node.key == key)
|
||||
if (shallow) return startAt
|
||||
@@ -360,7 +348,7 @@ const Node = {
|
||||
const child = this.nodes.find(node => {
|
||||
return node.kind == 'text'
|
||||
? null
|
||||
: node.hasDeep(key)
|
||||
: node.hasDescendant(key)
|
||||
})
|
||||
|
||||
return child
|
||||
@@ -369,41 +357,58 @@ const Node = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the first text child node.
|
||||
* Get the furthest block parent of a node by `key`.
|
||||
*
|
||||
* @return {Text or Null} text
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getFirstText() {
|
||||
return this.getTextNodes().first() || null
|
||||
getFurthestBlock(key) {
|
||||
let node = this.getDescendant(key)
|
||||
let furthest = null
|
||||
|
||||
while (node = this.getClosestBlock(node)) {
|
||||
furthest = node
|
||||
}
|
||||
|
||||
return furthest
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the furthest inline parent of a node by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getFurthestInline(key) {
|
||||
let node = this.getDescendant(key)
|
||||
let furthest = null
|
||||
|
||||
while (node = this.getClosestInline(node)) {
|
||||
furthest = node
|
||||
}
|
||||
|
||||
return furthest
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the closest inline nodes for each text node in a `range`.
|
||||
*
|
||||
* @param {Selection} range
|
||||
* @return {OrderedMap} nodes
|
||||
* @return {List} nodes
|
||||
*/
|
||||
|
||||
getInlinesAtRange(range) {
|
||||
range = range.normalize(this)
|
||||
const node = this
|
||||
const texts = node.getTextsAtRange(range)
|
||||
const inlines = texts
|
||||
.map(text => node.getClosest(text, p => p.kind == 'inline'))
|
||||
.filter(inline => inline)
|
||||
|
||||
return inlines
|
||||
},
|
||||
// If the range isn't set, return an empty list.
|
||||
if (range.isUnset) return Inline.createList()
|
||||
|
||||
/**
|
||||
* Get the last text child node.
|
||||
*
|
||||
* @return {Text or Null} text
|
||||
*/
|
||||
|
||||
getLastText() {
|
||||
return this.getTextNodes().last() || null
|
||||
return this
|
||||
.getTextsAtRange(range)
|
||||
.map(text => this.getClosestInline(text))
|
||||
.filter(exists => exists)
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -415,65 +420,54 @@ const Node = {
|
||||
|
||||
getMarksAtRange(range) {
|
||||
range = range.normalize(this)
|
||||
const { startKey, startOffset, endKey } = range
|
||||
const { startKey, startOffset } = range
|
||||
const marks = Mark.createSet()
|
||||
|
||||
// If the selection isn't set, return nothing.
|
||||
if (startKey == null || endKey == null) return new Set()
|
||||
// If the range isn't set, return an empty set.
|
||||
if (range.isUnset) return marks
|
||||
|
||||
// If the range is collapsed, and at the start of the node, check the
|
||||
// previous text node.
|
||||
// If the range is collapsed at the start of the node, check the previous.
|
||||
if (range.isCollapsed && startOffset == 0) {
|
||||
const previous = this.getPreviousText(startKey)
|
||||
if (!previous) return new Set()
|
||||
if (!previous) return marks
|
||||
const char = text.characters.get(previous.length - 1)
|
||||
return char.marks
|
||||
}
|
||||
|
||||
// If the range is collapsed, check the character before the start.
|
||||
if (range.isCollapsed) {
|
||||
const text = this.getDeep(startKey)
|
||||
const text = this.getDescendant(startKey)
|
||||
const char = text.characters.get(range.startOffset - 1)
|
||||
return char.marks
|
||||
}
|
||||
|
||||
// Otherwise, get a set of the marks for each character in the range.
|
||||
const characters = this.getCharactersAtRange(range)
|
||||
let set = new Set()
|
||||
|
||||
characters.forEach((char) => {
|
||||
set = set.union(char.marks)
|
||||
})
|
||||
|
||||
return set
|
||||
this
|
||||
.getCharactersAtRange(range)
|
||||
.reduce((marks, char) => {
|
||||
return marks.union(char.marks)
|
||||
}, marks)
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the child node after the one by `key`.
|
||||
* Get the node after a descendant by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null}
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getNextSibling(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
|
||||
const shallow = this.nodes.find(node => node.key == key)
|
||||
if (shallow) {
|
||||
return this.nodes
|
||||
.skipUntil(node => node.key == key)
|
||||
.rest()
|
||||
.first()
|
||||
}
|
||||
|
||||
return this.nodes
|
||||
.map(node => node.kind == 'text' ? null : node.getNextSibling(key))
|
||||
.filter(node => node)
|
||||
.first()
|
||||
const node = this.getDescendant(key)
|
||||
if (!node) return null
|
||||
return this
|
||||
.getParent(node)
|
||||
.nodes
|
||||
.skipUntil(child => child == node)
|
||||
.get(1)
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the text node after a text node by `key`.
|
||||
* Get the text node after a descendant text node by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null} node
|
||||
@@ -481,16 +475,13 @@ const Node = {
|
||||
|
||||
getNextText(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
|
||||
return this.getTextNodes()
|
||||
.skipUntil(text => text.key == key)
|
||||
.take(2)
|
||||
.last()
|
||||
.get(1)
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the offset for a child text node by `key`.
|
||||
* Get the offset for a descendant text node by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Number} offset
|
||||
@@ -498,16 +489,16 @@ const Node = {
|
||||
|
||||
getOffset(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
this.assertHasDescendant(key)
|
||||
|
||||
const match = this.getDeep(key)
|
||||
const match = this.getDescendant(key)
|
||||
|
||||
// Find the shallow matching child.
|
||||
const child = this.nodes.find((node) => {
|
||||
if (node == match) return true
|
||||
return node.kind == 'text'
|
||||
? false
|
||||
: node.hasDeep(match)
|
||||
: node.hasDescendant(match)
|
||||
})
|
||||
|
||||
// Get all of the nodes that come before the matching child.
|
||||
@@ -529,17 +520,15 @@ const Node = {
|
||||
* Get the parent of a child node by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null}
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getParent(key) {
|
||||
key = normalizeKey(key)
|
||||
// this.assertHasDeep(key)
|
||||
|
||||
const shallow = this.nodes.find(node => node.key == key)
|
||||
if (shallow) return this
|
||||
if (this.hasChild(key)) return this
|
||||
|
||||
let node = null
|
||||
|
||||
this.nodes.forEach((child) => {
|
||||
if (child.kind == 'text') return
|
||||
const match = child.getParent(key)
|
||||
@@ -550,31 +539,24 @@ const Node = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the child node before the one by `key`.
|
||||
* Get the node before a descendant node by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null}
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getPreviousSibling(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
|
||||
const shallow = this.nodes.find(node => node.key == key)
|
||||
if (shallow) {
|
||||
return this.nodes
|
||||
.takeUntil(node => node.key == key)
|
||||
.last()
|
||||
}
|
||||
|
||||
return this.nodes
|
||||
.map(node => node.kind == 'text' ? null : node.getPreviousSibling(key))
|
||||
.filter(node => node)
|
||||
.first()
|
||||
const node = this.getDescendant(key)
|
||||
if (!node) return null
|
||||
return this
|
||||
.getParent(node)
|
||||
.nodes
|
||||
.takeUntil(child => child == node)
|
||||
.last()
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the text node before a text node by `key`.
|
||||
* Get the text node before a descendant text node by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Node or Null} node
|
||||
@@ -582,35 +564,32 @@ const Node = {
|
||||
|
||||
getPreviousText(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
|
||||
return this.getTextNodes()
|
||||
.takeUntil(text => text.key == key)
|
||||
.last()
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the child text node at an `offset`.
|
||||
* Get the descendent text node at an `offset`.
|
||||
*
|
||||
* @param {String} offset
|
||||
* @return {Node or Null}
|
||||
* @return {Node or Null} node
|
||||
*/
|
||||
|
||||
getTextAtOffset(offset) {
|
||||
let length = 0
|
||||
let texts = this.getTextNodes()
|
||||
let match = texts.find((node) => {
|
||||
length += node.length
|
||||
return length >= offset
|
||||
})
|
||||
|
||||
return match
|
||||
return this
|
||||
.getTextNodes()
|
||||
.find((text) => {
|
||||
length += text.length
|
||||
return length >= offset
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Recursively get all of the child text nodes in order of appearance.
|
||||
*
|
||||
* @return {OrderedMap} nodes
|
||||
* @return {List} nodes
|
||||
*/
|
||||
|
||||
getTextNodes() {
|
||||
@@ -625,43 +604,49 @@ const Node = {
|
||||
* Get all of the text nodes in a `range`.
|
||||
*
|
||||
* @param {Selection} range
|
||||
* @return {OrderedMap} nodes
|
||||
* @return {List} nodes
|
||||
*/
|
||||
|
||||
getTextsAtRange(range) {
|
||||
range = range.normalize(this)
|
||||
|
||||
// If the selection is unset, return an empty list.
|
||||
if (range.isUnset) return Block.createList()
|
||||
|
||||
const { startKey, endKey } = range
|
||||
|
||||
// If the selection is unset, return an empty map.
|
||||
if (range.isUnset) return new OrderedMap()
|
||||
|
||||
// Assert that the nodes exist before searching.
|
||||
this.assertHasDeep(startKey)
|
||||
this.assertHasDeep(endKey)
|
||||
|
||||
// Return the text nodes after the start offset and before the end offset.
|
||||
const texts = this.getTextNodes()
|
||||
const endNode = this.getDeep(endKey)
|
||||
const afterStart = texts.skipUntil(node => node.key == startKey)
|
||||
const upToEnd = afterStart.takeUntil(node => node.key == endKey)
|
||||
const matches = upToEnd.push(endNode)
|
||||
return matches
|
||||
const startText = this.getDescendant(startKey)
|
||||
const endText = this.getDescendant(endKey)
|
||||
const start = texts.indexOf(startText)
|
||||
const end = texts.indexOf(endText)
|
||||
return texts.slice(start, end + 1)
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a child node exists by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Boolean} exists
|
||||
*/
|
||||
|
||||
hasChild(key) {
|
||||
key = normalizeKey(key)
|
||||
return !! this.nodes.find(node => node.key == key)
|
||||
},
|
||||
|
||||
/**
|
||||
* Recursively check if a child node exists by `key`.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {Boolean} true
|
||||
* @return {Boolean} exists
|
||||
*/
|
||||
|
||||
hasDeep(key) {
|
||||
hasDescendant(key) {
|
||||
key = normalizeKey(key)
|
||||
|
||||
return !! this.nodes.find((node) => {
|
||||
return node.kind == 'text'
|
||||
? node.key == key
|
||||
: node.key == key || node.hasDeep(key)
|
||||
: node.key == key || node.hasDescendant(key)
|
||||
})
|
||||
},
|
||||
|
||||
@@ -684,7 +669,7 @@ const Node = {
|
||||
}
|
||||
|
||||
let { startKey, startOffset } = range
|
||||
let startNode = node.getDeep(startKey)
|
||||
let startNode = node.getDescendant(startKey)
|
||||
let { characters } = startNode
|
||||
|
||||
// Create a list of the new characters, with the marks from the previous
|
||||
@@ -764,7 +749,7 @@ const Node = {
|
||||
let node = this
|
||||
|
||||
// See if there are any adjacent text nodes.
|
||||
let firstAdjacent = node.findDeep((child) => {
|
||||
let firstAdjacent = node.findDescendant((child) => {
|
||||
if (child.kind != 'text') return
|
||||
const parent = node.getParent(child)
|
||||
const next = parent.getNextSibling(child)
|
||||
@@ -782,7 +767,7 @@ const Node = {
|
||||
parent = parent.updateDeep(firstAdjacent)
|
||||
|
||||
// Then remove the second node.
|
||||
parent = parent.removeDeep(second)
|
||||
parent = parent.removeDescendant(second)
|
||||
|
||||
// If the parent isn't this node, it needs to be updated.
|
||||
if (parent != node) {
|
||||
@@ -795,18 +780,6 @@ const Node = {
|
||||
return node.normalize()
|
||||
},
|
||||
|
||||
/**
|
||||
* Push a new `node` onto the map of nodes.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {Node} node
|
||||
*/
|
||||
|
||||
pushNode(node) {
|
||||
const nodes = this.nodes.push(node)
|
||||
return this.merge({ nodes })
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a `node` from the children node map.
|
||||
*
|
||||
@@ -814,9 +787,9 @@ const Node = {
|
||||
* @return {Node} node
|
||||
*/
|
||||
|
||||
removeDeep(key) {
|
||||
removeDescendant(key) {
|
||||
key = normalizeKey(key)
|
||||
this.assertHasDeep(key)
|
||||
this.assertHasDescendant(key)
|
||||
const nodes = this.nodes.filterNot(node => node.key == key)
|
||||
return this.merge({ nodes })
|
||||
},
|
||||
@@ -913,14 +886,14 @@ const Node = {
|
||||
|
||||
// Find the highest inline elements that were split.
|
||||
const { startKey } = range
|
||||
const firstText = node.getDeep(startKey)
|
||||
const firstText = node.getDescendant(startKey)
|
||||
const firstChild = node.getFurthestInline(firstText) || firstText
|
||||
const secondText = node.getNextText(startKey)
|
||||
const secondChild = node.getFurthestInline(secondText) || secondText
|
||||
|
||||
// Remove the second inline child from the first block.
|
||||
let firstBlock = node.getBlocksAtRange(range).first()
|
||||
firstBlock = firstBlock.removeDeep(secondChild)
|
||||
firstBlock = firstBlock.removeDescendant(secondChild)
|
||||
|
||||
// Create a new block with the second inline child in it.
|
||||
const secondBlock = Block.create({
|
||||
@@ -961,7 +934,7 @@ const Node = {
|
||||
|
||||
// First split the text nodes.
|
||||
node = node.splitTextAtRange(range)
|
||||
let firstChild = node.getDeep(range.startKey)
|
||||
let firstChild = node.getDescendant(range.startKey)
|
||||
let secondChild = node.getNextText(firstChild)
|
||||
let parent
|
||||
|
||||
@@ -1010,7 +983,7 @@ const Node = {
|
||||
|
||||
// Split the text node's characters.
|
||||
const { startKey, startOffset } = range
|
||||
const text = node.getDeep(startKey)
|
||||
const text = node.getDescendant(startKey)
|
||||
const { characters } = text
|
||||
const firstChars = characters.take(startOffset)
|
||||
const secondChars = characters.skip(startOffset)
|
||||
@@ -1082,7 +1055,7 @@ const Node = {
|
||||
*/
|
||||
|
||||
updateDeep(node) {
|
||||
// this.assertHasDeep(key)
|
||||
// this.assertHasDescendant(key)
|
||||
|
||||
const shallow = this.nodes.find(child => child.key == node.key)
|
||||
if (shallow) {
|
||||
@@ -1235,7 +1208,7 @@ const Node = {
|
||||
|
||||
// Determine the new end of the range, and split there.
|
||||
const { startKey, startOffset, endKey, endOffset } = range
|
||||
const firstNode = node.getDeep(startKey)
|
||||
const firstNode = node.getDescendant(startKey)
|
||||
const nextNode = node.getNextText(startKey)
|
||||
const end = startKey != endKey
|
||||
? range.moveToEnd()
|
||||
@@ -1249,7 +1222,7 @@ const Node = {
|
||||
node = node.splitInlineAtRange(end)
|
||||
|
||||
// Calculate the new range to wrap around.
|
||||
const endNode = node.getDeep(end.anchorKey)
|
||||
const endNode = node.getDescendant(end.anchorKey)
|
||||
range = Selection.create({
|
||||
anchorKey: nextNode.key,
|
||||
anchorOffset: 0,
|
||||
|
@@ -114,7 +114,7 @@ class Selection extends Record(DEFAULTS) {
|
||||
|
||||
isAtStartOf(node) {
|
||||
const { startKey, startOffset } = this
|
||||
const first = node.kind == 'text' ? node : node.getFirstText()
|
||||
const first = node.kind == 'text' ? node : node.getTextNodes().first()
|
||||
return startKey == first.key && startOffset == 0
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ class Selection extends Record(DEFAULTS) {
|
||||
|
||||
isAtEndOf(node) {
|
||||
const { endKey, endOffset } = this
|
||||
const last = node.kind == 'text' ? node : node.getLastText()
|
||||
const last = node.kind == 'text' ? node : node.getTextNodes().last()
|
||||
return endKey == last.key && endOffset == last.length
|
||||
}
|
||||
|
||||
@@ -147,10 +147,10 @@ class Selection extends Record(DEFAULTS) {
|
||||
if (anchorKey == null || focusKey == null) return selection
|
||||
|
||||
// Asset that the anchor and focus nodes exist in the node tree.
|
||||
node.assertHasDeep(anchorKey)
|
||||
node.assertHasDeep(focusKey)
|
||||
let anchorNode = node.getDeep(anchorKey)
|
||||
let focusNode = node.getDeep(focusKey)
|
||||
node.assertHasDescendant(anchorKey)
|
||||
node.assertHasDescendant(focusKey)
|
||||
let anchorNode = node.getDescendant(anchorKey)
|
||||
let focusNode = node.getDescendant(focusKey)
|
||||
|
||||
// If the anchor node isn't a text node, match it to one.
|
||||
if (anchorNode.kind != 'text') {
|
||||
|
@@ -280,7 +280,7 @@ class State extends Record(DEFAULTS) {
|
||||
|
||||
// Determine what the selection should be after deleting.
|
||||
const { startKey } = selection
|
||||
const startNode = document.getDeep(startKey)
|
||||
const startNode = document.getDescendant(startKey)
|
||||
|
||||
if (selection.isExpanded) {
|
||||
after = selection.moveToStart()
|
||||
@@ -410,7 +410,7 @@ class State extends Record(DEFAULTS) {
|
||||
|
||||
// Determine what the selection should be after splitting.
|
||||
const { startKey } = selection
|
||||
const startNode = document.getDeep(startKey)
|
||||
const startNode = document.getDescendant(startKey)
|
||||
const parent = document.getParent(startNode)
|
||||
const next = document.getNext(parent)
|
||||
const text = next.nodes.first()
|
||||
|
Reference in New Issue
Block a user