mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-11 17:53:59 +02:00
Add normalize nodes to transforms bykey
This commit is contained in:
@@ -76,6 +76,7 @@
|
||||
"no-unreachable": "error",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-unused-vars": "warn",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-constructor": "error",
|
||||
|
@@ -25,7 +25,7 @@ const DOCUMENT_CHILDREN_RULE = {
|
||||
return invalids.size ? invalids : null
|
||||
},
|
||||
normalize: (transform, document, invalids) => {
|
||||
return invalids.reduce((t, n) => t.removeNodeByKey(n.key), transform)
|
||||
return invalids.reduce((t, n) => t.removeNodeByKey(n.key, { normalize: false }), transform)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const BLOCK_CHILDREN_RULE = {
|
||||
return invalids.size ? invalids : null
|
||||
},
|
||||
normalize: (transform, block, invalids) => {
|
||||
return invalids.reduce((t, n) => t.removeNodeByKey(n.key), transform)
|
||||
return invalids.reduce((t, n) => t.removeNodeByKey(n.key, { normalize: false }), transform)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ const MIN_TEXT_RULE = {
|
||||
return nodes.size === 0 ? true : null
|
||||
},
|
||||
normalize: (transform, node) => {
|
||||
return transform.insertNodeByKey(node.key, 0, Text.create())
|
||||
return transform.insertNodeByKey(node.key, 0, Text.create(), { normalize: false })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ const INLINE_CHILDREN_RULE = {
|
||||
return invalids.size ? invalids : null
|
||||
},
|
||||
normalize: (transform, inline, invalids) => {
|
||||
return invalids.reduce((t, n) => t.removeNodeByKey(n.key), transform)
|
||||
return invalids.reduce((t, n) => t.removeNodeByKey(n.key, { normalize: false }), transform)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ const INLINE_NO_EMPTY = {
|
||||
return inline.text == ''
|
||||
},
|
||||
normalize: (transform, node) => {
|
||||
return transform.removeNodeByKey(node.key)
|
||||
return transform.removeNodeByKey(node.key, { normalize: false })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,12 +119,12 @@ const INLINE_VOID_TEXT_RULE = {
|
||||
validate: (node) => {
|
||||
return node.text !== ' ' || node.nodes.size !== 1
|
||||
},
|
||||
normalize: (transform, node) => {
|
||||
normalize: (transform, node, result) => {
|
||||
transform = node.nodes.reduce((t, child) => {
|
||||
return t.removeNodeByKey(child.key)
|
||||
return t.removeNodeByKey(child.key, { normalize: false })
|
||||
}, transform)
|
||||
|
||||
return transform.insertNodeByKey(node.key, 0, Text.createFromString(' '))
|
||||
return transform.insertNodeByKey(node.key, 0, Text.createFromString(' '), { normalize: false })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,6 @@ const INLINE_VOID_TEXT_RULE = {
|
||||
|
||||
const INLINE_VOID_TEXTS_AROUND_RULE = {
|
||||
match: (object) => {
|
||||
return object.kind == 'block'
|
||||
return object.kind == 'block' || object.kind == 'inline'
|
||||
},
|
||||
validate: (block) => {
|
||||
@@ -162,8 +161,8 @@ const INLINE_VOID_TEXTS_AROUND_RULE = {
|
||||
},
|
||||
normalize: (transform, block, invalids) => {
|
||||
return invalids.reduce((t, { index, next, prev }) => {
|
||||
if (prev) t = transform.insertNodeByKey(block.key, index, Text.create())
|
||||
if (next) t = transform.insertNodeByKey(block.key, index + 1, Text.create())
|
||||
if (prev) t = transform.insertNodeByKey(block.key, index, Text.create(), { normalize: false })
|
||||
if (next) t = transform.insertNodeByKey(block.key, index + 1, Text.create(), { normalize: false })
|
||||
return t
|
||||
}, transform)
|
||||
}
|
||||
@@ -200,7 +199,7 @@ const NO_ADJACENT_TEXT_RULE = {
|
||||
.reverse()
|
||||
.reduce((t, pair) => {
|
||||
const [ first, second ] = pair
|
||||
return t.joinNodeByKey(second.key, first.key)
|
||||
return t.joinNodeByKey(second.key, first.key, { normalize: false })
|
||||
}, transform)
|
||||
}
|
||||
}
|
||||
@@ -256,7 +255,7 @@ const NO_EMPTY_TEXT_RULE = {
|
||||
},
|
||||
normalize: (transform, node, invalids) => {
|
||||
return invalids.reduce((t, text) => {
|
||||
return t.removeNodeByKey(text.key)
|
||||
return t.removeNodeByKey(text.key, { normalize: false })
|
||||
}, transform)
|
||||
}
|
||||
}
|
||||
|
@@ -482,6 +482,7 @@ const Raw = {
|
||||
untersifyBlock(object) {
|
||||
if (object.isVoid || !object.nodes || !object.nodes.length) {
|
||||
return {
|
||||
key: object.key,
|
||||
data: object.data,
|
||||
kind: object.kind,
|
||||
type: object.type,
|
||||
@@ -508,6 +509,7 @@ const Raw = {
|
||||
untersifyInline(object) {
|
||||
if (object.isVoid || !object.nodes || !object.nodes.length) {
|
||||
return {
|
||||
key: object.key,
|
||||
data: object.data,
|
||||
kind: object.kind,
|
||||
type: object.type,
|
||||
@@ -567,6 +569,7 @@ const Raw = {
|
||||
if (object.ranges) return object
|
||||
|
||||
return {
|
||||
key: object.key,
|
||||
kind: object.kind,
|
||||
ranges: [{
|
||||
text: object.text,
|
||||
|
@@ -1,7 +1,4 @@
|
||||
|
||||
import Text from '../models/text'
|
||||
import Normalize from '../utils/normalize'
|
||||
import uid from '../utils/uid'
|
||||
|
||||
/**
|
||||
* Add mark to text at `offset` and `length` in node by `key`.
|
||||
@@ -11,15 +8,25 @@ import uid from '../utils/uid'
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Mixed} mark
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function addMarkByKey(transform, key, offset, length, mark) {
|
||||
export function addMarkByKey(transform, key, offset, length, mark, options = {}) {
|
||||
const { normalize = true } = options
|
||||
mark = Normalize.mark(mark)
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const path = document.getPath(key)
|
||||
return transform.addMarkOperation(path, offset, length, mark)
|
||||
const parent = document.getParent(key)
|
||||
|
||||
transform = transform.addMarkOperation(path, offset, length, mark)
|
||||
if (normalize) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,16 +36,23 @@ export function addMarkByKey(transform, key, offset, length, mark) {
|
||||
* @param {String} key
|
||||
* @param {Number} index
|
||||
* @param {Node} node
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertNodeByKey(transform, key, index, node) {
|
||||
export function insertNodeByKey(transform, key, index, node, options = {}) {
|
||||
const { normalize = true } = options
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const path = document.getPath(key)
|
||||
const newPath = path.slice().push(index)
|
||||
|
||||
return transform.insertNodeOperation(path, index, node)
|
||||
transform = transform.insertNodeOperation(path, index, node)
|
||||
if (normalize) {
|
||||
transform = transform.normalizeNodeByKey(key)
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,14 +63,24 @@ export function insertNodeByKey(transform, key, index, node) {
|
||||
* @param {Number} offset
|
||||
* @param {String} text
|
||||
* @param {Set} marks (optional)
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function insertTextByKey(transform, key, offset, text, marks) {
|
||||
export function insertTextByKey(transform, key, offset, text, marks, options = {}) {
|
||||
const { normalize = true } = options
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const path = document.getPath(key)
|
||||
return transform.insertTextOperation(path, offset, text, marks)
|
||||
const parent = document.getParent(key)
|
||||
|
||||
transform = transform.insertTextOperation(path, offset, text, marks)
|
||||
if (normalize) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,15 +89,30 @@ export function insertTextByKey(transform, key, offset, text, marks) {
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {String} withKey
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function joinNodeByKey(transform, key, withKey) {
|
||||
export function joinNodeByKey(transform, key, withKey, options = {}) {
|
||||
const { normalize = true } = options
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const path = document.getPath(key)
|
||||
const withPath = document.getPath(withKey)
|
||||
return transform.joinNodeOperation(path, withPath)
|
||||
const parent = document.getCommonAncestor(key, withKey)
|
||||
|
||||
transform = transform.joinNodeOperation(path, withPath)
|
||||
|
||||
if (normalize) {
|
||||
if (parent) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
} else {
|
||||
transform = transform.normalizeDocument()
|
||||
}
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,20 +122,28 @@ export function joinNodeByKey(transform, key, withKey) {
|
||||
* @param {String} key
|
||||
* @param {String} newKey
|
||||
* @param {Number} index
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function moveNodeByKey(transform, key, newKey, newIndex) {
|
||||
export function moveNodeByKey(transform, key, newKey, newIndex, options = {}) {
|
||||
const { normalize = true } = options
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const node = document.assertDescendant(key)
|
||||
const prevParent = document.getParent(key)
|
||||
const path = document.getPath(key)
|
||||
const newPath = document.getPath(newKey)
|
||||
const parent = document.key == newKey ? document : document.assertDescendant(newKey)
|
||||
const previous = newIndex == 0 ? null : parent.nodes.get(newIndex - 1)
|
||||
const next = parent.nodes.get(newIndex)
|
||||
transform.moveNodeOperation(path, newPath, newIndex)
|
||||
|
||||
transform = transform.moveNodeOperation(path, newPath, newIndex)
|
||||
const parent = document.getCommonAncestor(key, newKey)
|
||||
|
||||
if (normalize) {
|
||||
if (parent) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
} else {
|
||||
transform = transform.normalizeDocument()
|
||||
}
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
@@ -109,15 +156,25 @@ export function moveNodeByKey(transform, key, newKey, newIndex) {
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeMarkByKey(transform, key, offset, length, mark) {
|
||||
export function removeMarkByKey(transform, key, offset, length, mark, options = {}) {
|
||||
const { normalize = true } = options
|
||||
mark = Normalize.mark(mark)
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const path = document.getPath(key)
|
||||
return transform.removeMarkOperation(path, offset, length, mark)
|
||||
const parent = document.getParent(key)
|
||||
|
||||
transform = transform.removeMarkOperation(path, offset, length, mark)
|
||||
if (normalize) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,19 +182,29 @@ export function removeMarkByKey(transform, key, offset, length, mark) {
|
||||
*
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeNodeByKey(transform, key) {
|
||||
export function removeNodeByKey(transform, key, options = {}) {
|
||||
const { normalize = true } = options
|
||||
const { state } = transform
|
||||
let { document } = state
|
||||
const node = document.assertDescendant(key)
|
||||
const path = document.getPath(key)
|
||||
const parent = document.getParent(key)
|
||||
const previous = document.getPreviousSibling(key)
|
||||
const next = document.getNextSibling(key)
|
||||
|
||||
return transform.removeNodeOperation(path)
|
||||
transform = transform.removeNodeOperation(path)
|
||||
|
||||
if (normalize) {
|
||||
if (parent) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
} else {
|
||||
transform = transform.normalizeDocument()
|
||||
}
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,16 +214,24 @@ export function removeNodeByKey(transform, key) {
|
||||
* @param {String} key
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function removeTextByKey(transform, key, offset, length) {
|
||||
export function removeTextByKey(transform, key, offset, length, options = {}) {
|
||||
const { normalize = true } = options
|
||||
const { state } = transform
|
||||
let { document } = state
|
||||
const path = document.getPath(key)
|
||||
const parent = document.getParent(key)
|
||||
return transform.removeTextOperation(path, offset, length)
|
||||
.normalizeNodeByKey(parent)
|
||||
|
||||
transform = transform.removeTextOperation(path, offset, length)
|
||||
if (normalize) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,16 +242,26 @@ export function removeTextByKey(transform, key, offset, length) {
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setMarkByKey(transform, key, offset, length, mark, properties) {
|
||||
export function setMarkByKey(transform, key, offset, length, mark, properties, options = {}) {
|
||||
const { normalize = true } = options
|
||||
mark = Normalize.mark(mark)
|
||||
properties = Normalize.markProperties(properties)
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const path = document.getPath(key)
|
||||
return transform.setMarkOperation(path, offset, length, mark, properties)
|
||||
const parent = document.getParent(key)
|
||||
|
||||
transform = transform.setMarkOperation(path, offset, length, mark, properties)
|
||||
if (normalize) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,15 +270,28 @@ export function setMarkByKey(transform, key, offset, length, mark, properties) {
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Object || String} properties
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function setNodeByKey(transform, key, properties) {
|
||||
export function setNodeByKey(transform, key, properties, options = {}) {
|
||||
const { normalize = true } = options
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const path = document.getPath(key)
|
||||
transform.setNodeOperation(path, properties)
|
||||
const parent = document.getParent(key)
|
||||
|
||||
transform = transform.setNodeOperation(path, properties)
|
||||
|
||||
if (normalize) {
|
||||
if (parent) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
} else {
|
||||
transform = transform.normalizeDocument()
|
||||
}
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
@@ -204,13 +302,27 @@ export function setNodeByKey(transform, key, properties) {
|
||||
* @param {Transform} transform
|
||||
* @param {String} key
|
||||
* @param {Number} offset
|
||||
* @param {Object} options
|
||||
* @param {Boolean} normalize
|
||||
* @return {Transform}
|
||||
*/
|
||||
|
||||
export function splitNodeByKey(transform, key, offset) {
|
||||
export function splitNodeByKey(transform, key, offset, options = {}) {
|
||||
const { normalize = true } = options
|
||||
let { state } = transform
|
||||
let { document } = state
|
||||
const path = document.getPath(key)
|
||||
const parent = document.getParent(key)
|
||||
|
||||
return transform.splitNodeOperation(path, offset)
|
||||
transform = transform.splitNodeOperation(path, offset)
|
||||
|
||||
if (normalize) {
|
||||
if (parent) {
|
||||
transform = transform.normalizeNodeByKey(parent.key)
|
||||
} else {
|
||||
transform = transform.normalizeDocument()
|
||||
}
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
import Schema from '../models/schema'
|
||||
import Raw from '../serializers/raw'
|
||||
import warning from '../utils/warning'
|
||||
import { default as defaultSchema } from '../plugins/schema'
|
||||
|
||||
@@ -30,8 +28,6 @@ function _refreshNode(transform, node) {
|
||||
*/
|
||||
|
||||
function _normalizeChildrenWith(transform, schema, node) {
|
||||
let { state } = transform
|
||||
|
||||
if (!node.nodes) {
|
||||
return transform
|
||||
}
|
||||
@@ -53,7 +49,6 @@ function _normalizeChildrenWith(transform, schema, node) {
|
||||
*/
|
||||
|
||||
function _normalizeNodeWith(transform, schema, node) {
|
||||
let { state } = transform
|
||||
const failure = schema.__validate(node)
|
||||
|
||||
// Node is valid?
|
||||
@@ -87,6 +82,7 @@ function _normalizeNodeWith(transform, schema, node) {
|
||||
*/
|
||||
|
||||
export function normalizeNodeWith(transform, schema, node) {
|
||||
// console.log(`normalize node key=${node.key}`)
|
||||
// Iterate over its children
|
||||
transform = _normalizeChildrenWith(transform, schema, node)
|
||||
|
||||
@@ -149,7 +145,7 @@ export function normalizeDocument(transform) {
|
||||
export function normalizeNodeByKey(transform, key) {
|
||||
const { state } = transform
|
||||
const { document } = state
|
||||
const node = document.assertDescendant(key)
|
||||
const node = document.key == key ? document : document.assertDescendant(key)
|
||||
|
||||
return transform.normalizeNodeWith(defaultSchema, node)
|
||||
}
|
||||
|
66
test.js
Normal file
66
test.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Raw, Inline } from './src'
|
||||
|
||||
function printNode(node, depth = 0) {
|
||||
const indent = Array(depth * 2).join(' ')
|
||||
|
||||
if (node.kind === 'text') {
|
||||
console.log(`${indent}#text key=${node.key}`)
|
||||
const ranges = node.getRanges()
|
||||
ranges.forEach(range => {
|
||||
console.log(`${indent} ${JSON.stringify(range.text)}`)
|
||||
})
|
||||
}
|
||||
else {
|
||||
console.log(`${indent}#${node.kind + (node.isVoid ? '(void)' : '')} type=${node.type} key=${node.key} ${node.data ? JSON.stringify(node.data.toJS()) : ''}`)
|
||||
node.nodes.forEach(child => printNode(child, depth + 1))
|
||||
}
|
||||
}
|
||||
|
||||
function print(st) {
|
||||
printNode(st.document)
|
||||
console.log('')
|
||||
}
|
||||
|
||||
const state = Raw.deserialize({
|
||||
nodes: [
|
||||
{
|
||||
kind: 'block',
|
||||
type: 'paragraph',
|
||||
key: 'container',
|
||||
nodes: [
|
||||
{
|
||||
key: 'in1',
|
||||
kind: 'inline',
|
||||
type: 'link',
|
||||
nodes: [
|
||||
{
|
||||
key: 'sometext',
|
||||
kind: 'text',
|
||||
text: 'Hello'
|
||||
},
|
||||
{
|
||||
key: 'in2',
|
||||
kind: 'inline',
|
||||
type: 'image',
|
||||
isVoid: true,
|
||||
nodes: [
|
||||
{
|
||||
kind: 'text',
|
||||
text: ' '
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, { terse: true })
|
||||
|
||||
print(state)
|
||||
|
||||
const newState = state.transform()
|
||||
.moveNodeByKey('in2', 'container')
|
||||
.apply()
|
||||
|
||||
print(newState)
|
Reference in New Issue
Block a user