1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-17 20:51:20 +02:00

Continue normalize next child when and only when the node exists still (#1538)

* Continue normalize next child when and only when the node exists still

* use the refindNode and refindPath provided

* Use Array.includes instead of Array.indexOf
This commit is contained in:
Jinxuan Zhu
2018-01-31 15:59:58 -05:00
committed by Ian Storm Taylor
parent 28450334a7
commit b1e5330ad5

View File

@@ -1,5 +1,4 @@
import { Set } from 'immutable'
/** /**
* Changes. * Changes.
@@ -68,41 +67,32 @@ function normalizeNodeAndChildren(change, node, schema) {
return return
} }
const normalizedKeys = []
let child = node.nodes.first()
let path = change.value.document.getPath(node.key)
// We can't just loop the children and normalize them, because in the process // We can't just loop the children and normalize them, because in the process
// of normalizing one child, we might end up creating another. Instead, we // of normalizing one child, we might end up creating another. Instead, we
// have to normalize one at a time, and check for new children along the way. // have to normalize one at a time, and check for new children along the way.
// PERF: use a mutable array here instead of an immutable stack. while (node && child) {
const keys = node.nodes.toArray().map(n => n.key) const lastSize = change.operations.size
normalizeNodeAndChildren(change, child, schema)
normalizedKeys.push(child.key)
// While there is still a child key that hasn't been normalized yet... // PERF: if size is unchanged, then no operation happens
while (keys.length) { // Therefore we can simply normalize the next child
const { size } = change.operations if (lastSize === change.operations.size) {
let key const nextIndex = node.nodes.indexOf(child) + 1
child = node.nodes.get(nextIndex)
// PERF: use a mutable set here since we'll be add to it a lot. } else {
let set = new Set().asMutable() node = change.value.document.refindNode(path, node.key)
if (!node) {
// Unwind the stack, normalizing every child and adding it to the set. path = []
while (key = keys[0]) { child = null
const child = node.getChild(key) } else {
normalizeNodeAndChildren(change, child, schema) path = change.value.document.refindPath(path, node.key)
set.add(key) child = node.nodes.find(c => !normalizedKeys.includes(c.key))
keys.shift() }
}
// Turn the set immutable to be able to compare against it.
set = set.asImmutable()
// PERF: Only re-find the node and re-normalize any new children if
// operations occured that might have changed it.
if (change.operations.size > size) {
node = refindNode(change, node)
// Add any new children back onto the stack.
node.nodes.forEach((n) => {
if (set.has(n.key)) return
keys.unshift(n.key)
})
} }
} }
@@ -112,23 +102,6 @@ function normalizeNodeAndChildren(change, node, schema) {
} }
} }
/**
* Re-find a reference to a node that may have been modified or removed
* entirely by a change.
*
* @param {Change} change
* @param {Node} node
* @return {Node}
*/
function refindNode(change, node) {
const { value } = change
const { document } = value
return node.object == 'document'
? document
: document.getDescendant(node.key)
}
/** /**
* Normalize a `node` with a `schema`, but not its children. * Normalize a `node` with a `schema`, but not its children.
* *
@@ -146,13 +119,16 @@ function normalizeNode(change, node, schema) {
if (!normalize) return if (!normalize) return
// Run the `normalize` function to fix the node. // Run the `normalize` function to fix the node.
let path = c.value.document.getPath(n.key)
normalize(c) normalize(c)
// Re-find the node reference, in case it was updated. If the node no longer // Re-find the node reference, in case it was updated. If the node no longer
// exists, we're done for this branch. // exists, we're done for this branch.
n = refindNode(c, n) n = c.value.document.refindNode(path, n.key)
if (!n) return if (!n) return
path = c.value.document.refindPath(path, n.key)
// Increment the iterations counter, and check to make sure that we haven't // Increment the iterations counter, and check to make sure that we haven't
// exceeded the max. Without this check, it's easy for the `validate` or // exceeded the max. Without this check, it's easy for the `validate` or
// `normalize` function of a schema rule to be written incorrectly and for // `normalize` function of a schema rule to be written incorrectly and for