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

Normalize children before normalizing a node itself

This commit is contained in:
Samy Pesse
2016-10-22 18:03:49 +02:00
parent 798a0a90f8
commit f73f63e6b9
4 changed files with 129 additions and 58 deletions

View File

@@ -52,8 +52,9 @@ class State extends new Record(DEFAULTS) {
} }
const state = new State({ document, selection }) const state = new State({ document, selection })
// transform.apply will normalize the document
return state.transform() return state.transform()
.normalize()
.apply({ save: false }) .apply({ save: false })
} }

View File

@@ -102,7 +102,7 @@ const INLINE_NO_EMPTY = {
return inline.text == '' return inline.text == ''
}, },
normalize: (transform, node) => { normalize: (transform, node) => {
return transform.removeNodeByKey(node.key) return transform.removeNodeByKey(node.key)
} }
} }
@@ -270,9 +270,9 @@ const schema = Schema.create({
rules: [ rules: [
DOCUMENT_CHILDREN_RULE, DOCUMENT_CHILDREN_RULE,
BLOCK_CHILDREN_RULE, BLOCK_CHILDREN_RULE,
MIN_TEXT_RULE,
INLINE_CHILDREN_RULE, INLINE_CHILDREN_RULE,
INLINE_VOID_TEXT_RULE, INLINE_VOID_TEXT_RULE,
MIN_TEXT_RULE,
INLINE_NO_EMPTY, INLINE_NO_EMPTY,
INLINE_VOID_TEXTS_AROUND_RULE, INLINE_VOID_TEXTS_AROUND_RULE,
NO_ADJACENT_TEXT_RULE, NO_ADJACENT_TEXT_RULE,

View File

@@ -147,6 +147,7 @@ import {
import { import {
normalize, normalize,
normalizeWith, normalizeWith,
normalizeNodeWith,
normalizeDocument, normalizeDocument,
normalizeSelection, normalizeSelection,
normalizeNodeByKey normalizeNodeByKey
@@ -293,6 +294,7 @@ export default {
normalize, normalize,
normalizeWith, normalizeWith,
normalizeNodeWith,
normalizeDocument, normalizeDocument,
normalizeSelection, normalizeSelection,
normalizeNodeByKey normalizeNodeByKey

View File

@@ -1,56 +1,124 @@
import Schema from '../models/schema' import Schema from '../models/schema'
import Raw from '../serializers/raw'
import warning from '../utils/warning' import warning from '../utils/warning'
import { default as defaultSchema } from '../plugins/schema' import { default as defaultSchema } from '../plugins/schema'
/** /**
* Normalize a node using a schema. * Refresh a reference to a node that have been modified in a transform.
* @param {Transform} transform
* @param {Node} node
* @return {Node} newNode
*/
function _refreshNode(transform, node) {
const { state } = transform
const { document } = state
if (node.kind == 'document') {
return document
}
return document.getDescendant(node.key)
}
/**
* Normalize all children of a node
* @param {Transform} transform
* @param {Schema} schema
* @param {Node} node
* @return {Transform} transform
*/
function _normalizeChildrenWith(transform, schema, node) {
let { state } = transform
if (!node.nodes) {
return transform
}
return node.nodes.reduce(
(t, child) => {
return t.normalizeNodeWith(schema, child)
},
transform
)
}
/**
* Normalize a node without its children
* @param {Transform} transform
* @param {Schema} schema
* @param {Node} node
* @return {Transform} transform
*/
function _normalizeNodeWith(transform, schema, node) {
let { state } = transform
const failure = schema.__validate(node)
// Node is valid?
if (!failure) {
return transform
}
const { value, rule } = failure
// Normalize and get the new state
transform = rule.normalize(transform, node, value)
// Search for the updated node in the new state
const newNode = _refreshNode(transform, node)
// Node no longer exist, go back to normalize parents
if (!newNode) {
return transform
}
return normalizeNodeWith(transform, schema, newNode)
}
/**
* Normalize a node (itself and its children) using a schema.
* *
* @param {Transform} transform * @param {Transform} transform
* @param {Node} node * @param {Schema} schema
* @param {Node} node
* @return {Transform} * @return {Transform}
*/ */
export function normalizeWith(transform, schema, node) { export function normalizeNodeWith(transform, schema, node) {
let { state } = transform // Iterate over its children
transform = _normalizeChildrenWith(transform, schema, node)
// If no node specific, normalize the whole document // Refresh the node reference, and normalize it
node = node || state.document node = _refreshNode(transform, node)
if (node) {
transform = _normalizeNodeWith(transform, schema, node)
}
const failure = schema.__validate(node) return transform
}
if (failure) { /**
const { value, rule } = failure * Normalize state using a schema.
*
* @param {Transform} transform
* @param {Schema} schema
* @return {Transform} transform
*/
// Normalize and get the new state export function normalizeWith(transform, schema) {
transform = rule.normalize(transform, node, value) const { state } = transform
const newState = transform.state const { document } = state
// Search for the updated node in the new state return transform.normalizeNodeWith(schema, document)
node = newState.document.getDescendant(node.key)
// Node no longer exist, exit
if (!node) {
return transform
}
return transform.normalizeWith(schema, node)
}
// No child, stop here
if (!node.nodes) {
return transform
}
return node.nodes.reduce((t, child) => {
return t.normalizeWith(schema, child)
}, transform)
} }
/** /**
* Normalize the state using the core schema. * Normalize the state using the core schema.
* *
* @param {Transform} transform * @param {Transform} transform
* @return {Transform} * @return {Transform} transform
*/ */
export function normalize(transform) { export function normalize(transform) {
@@ -60,10 +128,10 @@ export function normalize(transform) {
} }
/** /**
* Normalize the whole document * Normalize only the document
* *
* @param {Transform} transform * @param {Transform} transform
* @return {Transform} * @return {Transform} transform
*/ */
export function normalizeDocument(transform) { export function normalizeDocument(transform) {
@@ -71,10 +139,11 @@ export function normalizeDocument(transform) {
} }
/** /**
* Normalize a specific node of the document using core schema * Normalize a specific node using core schema
* *
* @param {Transform} transform * @param {Transform} transform
* @return {Transform} * @param {Node or String} key
* @return {Transform} transform
*/ */
export function normalizeNodeByKey(transform, key) { export function normalizeNodeByKey(transform, key) {
@@ -82,14 +151,14 @@ export function normalizeNodeByKey(transform, key) {
const { document } = state const { document } = state
const node = document.assertDescendant(key) const node = document.assertDescendant(key)
return transform.normalizeWith(defaultSchema, node) return transform.normalizeNodeWith(defaultSchema, node)
} }
/** /**
* Normalize the selection. * Normalize only the selection.
* *
* @param {Transform} transform * @param {Transform} transform
* @return {Transform} * @return {Transform} transform
*/ */
export function normalizeSelection(transform) { export function normalizeSelection(transform) {
@@ -99,20 +168,19 @@ export function normalizeSelection(transform) {
// If the selection is nulled (not normal) // If the selection is nulled (not normal)
if ( if (
selection.anchorKey == null || selection.isUnset ||
selection.focusKey == null ||
!document.hasDescendant(selection.anchorKey) || !document.hasDescendant(selection.anchorKey) ||
!document.hasDescendant(selection.focusKey) !document.hasDescendant(selection.focusKey)
) { ) {
warning('Selection was invalid and reset to start of the document') warning('Selection was invalid and reset to start of the document')
const firstText = document.getTexts().first() const firstText = document.getTexts().first()
selection = selection.merge({ selection = selection.merge({
anchorKey: firstText.key, anchorKey: firstText.key,
anchorOffset: 0, anchorOffset: 0,
focusKey: firstText.key, focusKey: firstText.key,
focusOffset: 0, focusOffset: 0,
isBackward: false isBackward: false
}) })
} }
state = state.merge({ selection }) state = state.merge({ selection })