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

change from ordered map to list for nodes

This commit is contained in:
Ian Storm Taylor
2016-06-23 11:32:24 -07:00
parent a3c4c04193
commit d637d9e053
10 changed files with 83 additions and 129 deletions

View File

@@ -4,7 +4,7 @@ import Inline from './inline'
import Node from './node' import Node from './node'
import Text from './text' import Text from './text'
import uid from 'uid' import uid from 'uid'
import Immutable, { Map, OrderedMap, Record } from 'immutable' import Immutable, { Map, List, Record } from 'immutable'
/** /**
* Default properties. * Default properties.
@@ -13,7 +13,7 @@ import Immutable, { Map, OrderedMap, Record } from 'immutable'
const DEFAULTS = { const DEFAULTS = {
data: new Map(), data: new Map(),
key: null, key: null,
nodes: new OrderedMap(), nodes: new List(),
type: null type: null
} }
@@ -38,26 +38,21 @@ class Block extends Record(DEFAULTS) {
properties.key = uid(4) properties.key = uid(4)
properties.data = Data.create(properties.data) properties.data = Data.create(properties.data)
properties.nodes = Block.createMap(properties.nodes) properties.nodes = Block.createList(properties.nodes)
let block = new Block(properties) return new Block(properties).normalize()
return block.normalize()
} }
/** /**
* Create an ordered map of `Blocks` from an array of `Blocks`. * Create a list of `Blocks` from an array.
* *
* @param {Array} elements * @param {Array} elements
* @return {OrderedMap} map * @return {List} list
*/ */
static createMap(elements = []) { static createList(elements = []) {
if (OrderedMap.isOrderedMap(elements)) return elements if (List.isList(elements)) return elements
return elements return new List(elements.map(Block.create))
.map(Block.create)
.reduce((map, element) => {
return map.set(element.key, element)
}, new OrderedMap())
} }
/** /**

View File

@@ -26,11 +26,8 @@ class Document extends Record(DEFAULTS) {
static create(properties = {}) { static create(properties = {}) {
if (properties instanceof Document) return properties if (properties instanceof Document) return properties
properties.nodes = Block.createList(properties.nodes)
properties.nodes = Block.createMap(properties.nodes) return new Document(properties).normalize()
let document = new Document(properties)
return document.normalize()
} }
/** /**

View File

@@ -4,7 +4,7 @@ import Data from './data'
import Node from './node' import Node from './node'
import Text from './text' import Text from './text'
import uid from 'uid' import uid from 'uid'
import Immutable, { Map, OrderedMap, Record } from 'immutable' import { List, Map, Record } from 'immutable'
/** /**
* Record. * Record.
@@ -13,7 +13,7 @@ import Immutable, { Map, OrderedMap, Record } from 'immutable'
const DEFAULTS = { const DEFAULTS = {
data: new Map(), data: new Map(),
key: null, key: null,
nodes: new OrderedMap(), nodes: new List(),
type: null type: null
} }
@@ -38,26 +38,22 @@ class Inline extends Record(DEFAULTS) {
properties.key = uid(4) properties.key = uid(4)
properties.data = Data.create(properties.data) properties.data = Data.create(properties.data)
properties.nodes = Inline.createMap(properties.nodes) properties.nodes = Inline.createList(properties.nodes)
let inline = new Inline(properties) let inline = new Inline(properties)
return inline.normalize() return inline.normalize()
} }
/** /**
* Create an ordered map of `Inlines` from an array of `Inlines`. * Create a list of `Inlines` from an array.
* *
* @param {Array} elements * @param {Array} elements
* @return {OrderedMap} map * @return {List} map
*/ */
static createMap(elements = []) { static createList(elements = []) {
if (OrderedMap.isOrderedMap(elements)) return elements if (List.isList(elements)) return elements
return elements return new List(elements.map(Inline.create))
.map(Inline.create)
.reduce((map, element) => {
return map.set(element.key, element)
}, new OrderedMap())
} }
/** /**

View File

@@ -27,9 +27,7 @@ class Mark extends Record(DEFAULTS) {
static create(properties = {}) { static create(properties = {}) {
if (properties instanceof Mark) return properties if (properties instanceof Mark) return properties
if (!properties.type) throw new Error('You must provide a `type` for the mark.') if (!properties.type) throw new Error('You must provide a `type` for the mark.')
properties.data = Data.create(properties.data) properties.data = Data.create(properties.data)
return new Mark(properties) return new Mark(properties)
} }

View File

@@ -5,7 +5,7 @@ import Data from './data'
import Mark from './mark' import Mark from './mark'
import Selection from './selection' import Selection from './selection'
import Text from './text' import Text from './text'
import { List, Map, OrderedMap, OrderedSet, Set } from 'immutable' import { List, Map, Set } from 'immutable'
/** /**
* Node. * Node.
@@ -49,9 +49,7 @@ const Node = {
// If the start and end nodes are the same, remove the matching characters. // If the start and end nodes are the same, remove the matching characters.
if (startKey == endKey) { if (startKey == endKey) {
let { characters } = startNode const characters = startNode.characters.filterNot((char, i) => {
characters = characters.filterNot((char, i) => {
return startOffset <= i && i < endOffset return startOffset <= i && i < endOffset
}) })
@@ -92,7 +90,7 @@ const Node = {
const nodes = node.nodes const nodes = node.nodes
.takeUntil(child => child == startGrandestParent) .takeUntil(child => child == startGrandestParent)
.set(startGrandestParent.key, startGrandestParent) .push(startGrandestParent)
.concat(node.nodes.skipUntil(child => child == endGrandestParent)) .concat(node.nodes.skipUntil(child => child == endGrandestParent))
node = node.merge({ nodes }) node = node.merge({ nodes })
@@ -214,17 +212,11 @@ const Node = {
*/ */
filterDeep(iterator) { filterDeep(iterator) {
return this.nodes.reduce((matches, child) => { return this.nodes.reduce((matches, child, i, nodes) => {
if (iterator(child, child.key, this.nodes)) { if (iterator(child, i, nodes)) matches = matches.push(child)
matches = matches.set(child.key, child) if (child.kind != 'text') matches = matches.concat(child.filterDeep(iterator))
}
if (child.kind != 'text') {
matches = matches.concat(child.filterDeep(iterator))
}
return matches return matches
}, new OrderedMap()) }, Block.createList())
}, },
/** /**
@@ -362,7 +354,8 @@ const Node = {
key = normalizeKey(key) key = normalizeKey(key)
this.assertHasDeep(key) this.assertHasDeep(key)
if (this.nodes.has(key)) return startAt const shallow = this.nodes.find(node => node.key == key)
if (shallow) return startAt
const child = this.nodes.find(node => { const child = this.nodes.find(node => {
return node.kind == 'text' return node.kind == 'text'
@@ -465,7 +458,8 @@ const Node = {
key = normalizeKey(key) key = normalizeKey(key)
this.assertHasDeep(key) this.assertHasDeep(key)
if (this.nodes.has(key)) { const shallow = this.nodes.find(node => node.key == key)
if (shallow) {
return this.nodes return this.nodes
.skipUntil(node => node.key == key) .skipUntil(node => node.key == key)
.rest() .rest()
@@ -526,7 +520,7 @@ const Node = {
// If the child's parent is this node, return the offset of all of the nodes // If the child's parent is this node, return the offset of all of the nodes
// before it, otherwise recurse. // before it, otherwise recurse.
return this.nodes.has(match.key) return this.nodes.find(node => node.key == match.key)
? offset ? offset
: offset + child.getOffset(key) : offset + child.getOffset(key)
}, },
@@ -542,7 +536,8 @@ const Node = {
key = normalizeKey(key) key = normalizeKey(key)
// this.assertHasDeep(key) // this.assertHasDeep(key)
if (this.nodes.has(key)) return this const shallow = this.nodes.find(node => node.key == key)
if (shallow) return this
let node = null let node = null
this.nodes.forEach((child) => { this.nodes.forEach((child) => {
@@ -565,7 +560,8 @@ const Node = {
key = normalizeKey(key) key = normalizeKey(key)
this.assertHasDeep(key) this.assertHasDeep(key)
if (this.nodes.has(key)) { const shallow = this.nodes.find(node => node.key == key)
if (shallow) {
return this.nodes return this.nodes
.takeUntil(node => node.key == key) .takeUntil(node => node.key == key)
.last() .last()
@@ -620,9 +616,9 @@ const Node = {
getTextNodes() { getTextNodes() {
return this.nodes.reduce((texts, node) => { return this.nodes.reduce((texts, node) => {
return node.kind == 'text' return node.kind == 'text'
? texts.set(node.key, node) ? texts.push(node)
: texts.concat(node.getTextNodes()) : texts.concat(node.getTextNodes())
}, new OrderedMap()) }, Block.createList())
}, },
/** /**
@@ -648,7 +644,7 @@ const Node = {
const endNode = this.getDeep(endKey) const endNode = this.getDeep(endKey)
const afterStart = texts.skipUntil(node => node.key == startKey) const afterStart = texts.skipUntil(node => node.key == startKey)
const upToEnd = afterStart.takeUntil(node => node.key == endKey) const upToEnd = afterStart.takeUntil(node => node.key == endKey)
const matches = upToEnd.set(endNode.key, endNode) const matches = upToEnd.push(endNode)
return matches return matches
}, },
@@ -802,18 +798,12 @@ const Node = {
/** /**
* Push a new `node` onto the map of nodes. * Push a new `node` onto the map of nodes.
* *
* @param {String or Node} key * @param {Node} node
* @param {Node} node (optional)
* @return {Node} node * @return {Node} node
*/ */
pushNode(key, node) { pushNode(node) {
if (arguments.length == 1) { const nodes = this.nodes.push(node)
node = key
key = normalizeKey(key)
}
let nodes = this.nodes.set(key, node)
return this.merge({ nodes }) return this.merge({ nodes })
}, },
@@ -827,8 +817,7 @@ const Node = {
removeDeep(key) { removeDeep(key) {
key = normalizeKey(key) key = normalizeKey(key)
this.assertHasDeep(key) this.assertHasDeep(key)
const nodes = this.nodes.filterNot(node => node.key == key)
let nodes = this.nodes.remove(key)
return this.merge({ nodes }) return this.merge({ nodes })
}, },
@@ -943,8 +932,8 @@ const Node = {
// Replace the block in the parent with the two new blocks. // Replace the block in the parent with the two new blocks.
let parent = node.getParent(firstBlock) let parent = node.getParent(firstBlock)
const nodes = parent.nodes.takeUntil(n => n.key == firstBlock.key) const nodes = parent.nodes.takeUntil(n => n.key == firstBlock.key)
.set(firstBlock.key, firstBlock) .push(firstBlock)
.set(secondBlock.key, secondBlock) .push(secondBlock)
.concat(parent.nodes.skipUntil(n => n.key == firstBlock.key).rest()) .concat(parent.nodes.skipUntil(n => n.key == firstBlock.key).rest())
// If the node is the parent, just merge, otherwise deep merge. // If the node is the parent, just merge, otherwise deep merge.
@@ -960,7 +949,6 @@ const Node = {
}, },
splitInlineAtRange(range) { splitInlineAtRange(range) {
debugger
range = range.normalize(this) range = range.normalize(this)
const Inline = require('./inline').default const Inline = require('./inline').default
let node = this let node = this
@@ -979,7 +967,7 @@ const Node = {
// While the parent is an inline parent, split the inline nodes. // While the parent is an inline parent, split the inline nodes.
while (parent = node.getClosestInline(firstChild)) { while (parent = node.getClosestInline(firstChild)) {
firstChild = parent.merge({ nodes: Inline.createMap([firstChild]) }) firstChild = parent.merge({ nodes: Inline.createList([firstChild]) })
secondChild = Inline.create({ secondChild = Inline.create({
nodes: [secondChild], nodes: [secondChild],
type: parent.type, type: parent.type,
@@ -987,16 +975,15 @@ const Node = {
}) })
// Split the children. // Split the children.
const isGrandparent = node.nodes.has(parent.key) const grandparent = node.getParent(parent)
const grandparent = isGrandparent ? node : node.getParent(parent)
const nodes = grandparent.nodes const nodes = grandparent.nodes
.takeUntil(c => c.key == firstChild.key) .takeUntil(c => c.key == firstChild.key)
.set(firstChild.key, firstChild) .push(firstChild)
.set(secondChild.key, secondChild) .push(secondChild)
.concat(grandparent.nodes.skipUntil(n => n.key == firstChild.key).rest()) .concat(grandparent.nodes.skipUntil(n => n.key == firstChild.key).rest())
// Update the grandparent. // Update the grandparent.
node = isGrandparent node = grandparent == node
? node.merge({ nodes }) ? node.merge({ nodes })
: node.updateDeep(grandparent.merge({ nodes })) : node.updateDeep(grandparent.merge({ nodes }))
} }
@@ -1034,8 +1021,8 @@ const Node = {
let parent = node.getParent(text) let parent = node.getParent(text)
const nodes = parent.nodes const nodes = parent.nodes
.takeUntil(c => c.key == firstChild.key) .takeUntil(c => c.key == firstChild.key)
.set(firstChild.key, firstChild) .push(firstChild)
.set(secondChild.key, secondChild) .push(secondChild)
.concat(parent.nodes.skipUntil(n => n.key == firstChild.key).rest()) .concat(parent.nodes.skipUntil(n => n.key == firstChild.key).rest())
// Update the nodes. // Update the nodes.
@@ -1090,26 +1077,21 @@ const Node = {
/** /**
* Set a new value for a child node by `key`. * Set a new value for a child node by `key`.
* *
* @param {String or Node} key * @param {Node} node
* @param {Node} node (optional)
* @return {Node} node * @return {Node} node
*/ */
updateDeep(key, node) { updateDeep(node) {
if (arguments.length == 1) {
node = key
key = normalizeKey(key)
}
// this.assertHasDeep(key) // this.assertHasDeep(key)
if (this.nodes.get(key)) { const shallow = this.nodes.find(child => child.key == node.key)
const nodes = this.nodes.set(key, node) if (shallow) {
return this.set('nodes', nodes) const nodes = this.nodes.map(child => child.key == node.key ? node : child)
return this.merge({ nodes })
} }
const nodes = this.nodes.map((child) => { const nodes = this.nodes.map((child) => {
return child.kind == 'text' ? child : child.updateDeep(key, node) return child.kind == 'text' ? child : child.updateDeep(node)
}) })
return this.merge({ nodes }) return this.merge({ nodes })
@@ -1146,9 +1128,9 @@ const Node = {
const sibling = node.getDepth(block) == depth const sibling = node.getDepth(block) == depth
? block ? block
: node.getClosest(block, (p) => node.getDepth(p) == depth) : node.getClosest(block, (p) => node.getDepth(p) == depth)
siblings = siblings.set(sibling.key, sibling) siblings = siblings.push(sibling)
return siblings return siblings
}, new OrderedMap()) }, Block.createList())
// Wrap the siblings in a new block. // Wrap the siblings in a new block.
const wrapper = Block.create({ const wrapper = Block.create({
@@ -1158,20 +1140,16 @@ const Node = {
}) })
// Replace the siblings with the wrapper. // Replace the siblings with the wrapper.
const isDirectChild = node.nodes.has(highest.key) const parent = node.getParent(highest)
let parent = isDirectChild ? node : node.getParent(highest)
const nodes = parent.nodes const nodes = parent.nodes
.takeUntil(node => node == highest) .takeUntil(node => node == highest)
.set(wrapper.key, wrapper) .push(wrapper)
.concat(parent.nodes.skipUntil(node => node == highest).rest()) .concat(parent.nodes.skipUntil(node => node == highest).rest())
// Update the parent. // Update the parent.
if (isDirectChild) { node = parent == node
node = node.merge({ nodes }) ? node.merge({ nodes })
} else { : node.updateDeep(parent.merge({ nodes }))
parent = parent.merge({ nodes })
node = node.updateDeep(parent)
}
return node return node
}, },
@@ -1208,14 +1186,13 @@ const Node = {
return true return true
}) })
if (match) wrappers = wrappers.set(match.key, match) if (match) wrappers = wrappers.add(match)
return wrappers return wrappers
}, new OrderedMap()) }, new Set())
// Replace each of the wrappers with their child nodes. // Replace each of the wrappers with their child nodes.
wrappers.forEach((wrapper) => { wrappers.forEach((wrapper) => {
const isDirectChild = node.nodes.has(wrapper.key) const parent = node.getParent(wrapper)
let parent = isDirectChild ? node : node.getParent(wrapper)
// Replace the wrapper in the parent's nodes with the block. // Replace the wrapper in the parent's nodes with the block.
const nodes = parent.nodes.takeUntil(n => n == wrapper) const nodes = parent.nodes.takeUntil(n => n == wrapper)
@@ -1223,12 +1200,9 @@ const Node = {
.concat(parent.nodes.skipUntil(n => n == wrapper).rest()) .concat(parent.nodes.skipUntil(n => n == wrapper).rest())
// Update the parent. // Update the parent.
if (isDirectChild) { node = parent == node
node = node.merge({ nodes }) ? node.merge({ nodes })
} else { : node.updateDeep(parent.merge({ nodes }))
parent = parent.merge({ nodes })
node = node.updateDeep(parent)
}
}) })
return node.normalize() return node.normalize()
@@ -1298,7 +1272,7 @@ const Node = {
// Replace the child in it's parent with the wrapper. // Replace the child in it's parent with the wrapper.
const parent = node.getParent(child) const parent = node.getParent(child)
const nodes = parent.nodes.takeUntil(n => n == child) const nodes = parent.nodes.takeUntil(n => n == child)
.set(wrapper.key, wrapper) .push(wrapper)
.concat(parent.nodes.skipUntil(n => n == child).rest()) .concat(parent.nodes.skipUntil(n => n == child).rest())
// Update the parent. // Update the parent.
@@ -1343,14 +1317,13 @@ const Node = {
return true return true
}) })
if (match) wrappers = wrappers.set(match.key, match) if (match) wrappers = wrappers.add(match)
return wrappers return wrappers
}, new OrderedMap()) }, new Set())
// Replace each of the wrappers with their child nodes. // Replace each of the wrappers with their child nodes.
wrappers.forEach((wrapper) => { wrappers.forEach((wrapper) => {
const parent = node.getParent(wrapper) const parent = node.getParent(wrapper)
const isDirectChild = parent == node
// Replace the wrapper in the parent's nodes with the block. // Replace the wrapper in the parent's nodes with the block.
const nodes = parent.nodes.takeUntil(n => n == wrapper) const nodes = parent.nodes.takeUntil(n => n == wrapper)
@@ -1358,7 +1331,7 @@ const Node = {
.concat(parent.nodes.skipUntil(n => n == wrapper).rest()) .concat(parent.nodes.skipUntil(n => n == wrapper).rest())
// Update the parent. // Update the parent.
node = isDirectChild node = parent == node
? node.merge({ nodes }) ? node.merge({ nodes })
: node.updateDeep(parent.merge({ nodes })) : node.updateDeep(parent.merge({ nodes }))
}) })

View File

@@ -60,10 +60,8 @@ class State extends Record(DEFAULTS) {
static create(properties = {}) { static create(properties = {}) {
if (properties instanceof State) return properties if (properties instanceof State) return properties
properties.document = Document.create(properties.document) properties.document = Document.create(properties.document)
properties.selection = Selection.create(properties.selection) properties.selection = Selection.create(properties.selection)
return new State(properties) return new State(properties)
} }

View File

@@ -27,10 +27,8 @@ class Text extends Record(DEFAULTS) {
static create(properties = {}) { static create(properties = {}) {
if (properties instanceof Text) return properties if (properties instanceof Text) return properties
properties.key = uid(4) properties.key = uid(4)
properties.characters = Character.createList(properties.characters) properties.characters = Character.createList(properties.characters)
return new Text(properties) return new Text(properties)
} }

View File

@@ -94,7 +94,7 @@ function serializeMark(mark) {
function deserialize(object) { function deserialize(object) {
return State.create({ return State.create({
document: Document.create({ document: Document.create({
nodes: Block.createMap(object.nodes.map(deserializeNode)) nodes: Block.createList(object.nodes.map(deserializeNode))
}) })
}) })
} }
@@ -111,15 +111,15 @@ function deserializeNode(object) {
case 'block': { case 'block': {
return Block.create({ return Block.create({
type: object.type, type: object.type,
data: new Map(object.data), data: object.data,
nodes: Block.createMap(object.nodes.map(deserializeNode)) nodes: Block.createList(object.nodes.map(deserializeNode))
}) })
} }
case 'inline': { case 'inline': {
return Inline.create({ return Inline.create({
type: object.type, type: object.type,
data: new Map(object.data), data: object.data,
nodes: Inline.createMap(object.nodes.map(deserializeNode)) nodes: Inline.createList(object.nodes.map(deserializeNode))
}) })
} }
case 'text': { case 'text': {
@@ -161,10 +161,7 @@ function deserializeRanges(array) {
*/ */
function deserializeMark(object) { function deserializeMark(object) {
return Mark.create({ return Mark.create(object)
type: object.type,
data: new Map(object.data)
})
} }
/** /**

View File

@@ -25,6 +25,7 @@
"mocha-phantomjs": "^4.0.2", "mocha-phantomjs": "^4.0.2",
"react-dom": "^15.1.0", "react-dom": "^15.1.0",
"read-metadata": "^1.0.0", "read-metadata": "^1.0.0",
"source-map-support": "^0.4.0",
"standard": "^7.1.2", "standard": "^7.1.2",
"to-camel-case": "^1.0.0", "to-camel-case": "^1.0.0",
"watchify": "^3.7.0" "watchify": "^3.7.0"

View File

@@ -1,2 +1,3 @@
import 'source-map-support/register'
import './transforms' import './transforms'