mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-20 06:01:24 +02:00
refactor normalizing function
This commit is contained in:
@@ -5,6 +5,7 @@ import Data from './data'
|
||||
import Document from './document'
|
||||
import Inline from './inline'
|
||||
import Mark from './mark'
|
||||
import Normalize from '../utils/normalize'
|
||||
import Selection from './selection'
|
||||
import Text from './text'
|
||||
import direction from 'direction'
|
||||
@@ -34,7 +35,7 @@ const Node = {
|
||||
const child = this.getChild(key)
|
||||
|
||||
if (!child) {
|
||||
key = normalizeKey(key)
|
||||
key = Normalize.key(key)
|
||||
throw new Error(`Could not find a child node with key "${key}".`)
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ const Node = {
|
||||
const descendant = this.getDescendant(key)
|
||||
|
||||
if (!descendant) {
|
||||
key = normalizeKey(key)
|
||||
key = Normalize.key(key)
|
||||
throw new Error(`Could not find a descendant node with key "${key}".`)
|
||||
}
|
||||
|
||||
@@ -308,7 +309,7 @@ const Node = {
|
||||
*/
|
||||
|
||||
getChild(key) {
|
||||
key = normalizeKey(key)
|
||||
key = Normalize.key(key)
|
||||
return this.nodes.find(node => node.key == key)
|
||||
},
|
||||
|
||||
@@ -390,7 +391,7 @@ const Node = {
|
||||
*/
|
||||
|
||||
getDescendant(key) {
|
||||
key = normalizeKey(key)
|
||||
key = Normalize.key(key)
|
||||
|
||||
let child = this.getChild(key)
|
||||
if (child) return child
|
||||
@@ -511,7 +512,7 @@ const Node = {
|
||||
*/
|
||||
|
||||
getHighestChild(key) {
|
||||
key = normalizeKey(key)
|
||||
key = Normalize.key(key)
|
||||
return this.nodes.find(node => {
|
||||
if (node.key == key) return true
|
||||
if (node.kind == 'text') return false
|
||||
@@ -653,7 +654,7 @@ const Node = {
|
||||
*/
|
||||
|
||||
getNextText(key) {
|
||||
key = normalizeKey(key)
|
||||
key = Normalize.key(key)
|
||||
return this.getTexts()
|
||||
.skipUntil(text => text.key == key)
|
||||
.get(1)
|
||||
@@ -744,7 +745,7 @@ const Node = {
|
||||
*/
|
||||
|
||||
getPreviousText(key) {
|
||||
key = normalizeKey(key)
|
||||
key = Normalize.key(key)
|
||||
return this.getTexts()
|
||||
.takeUntil(text => text.key == key)
|
||||
.last()
|
||||
@@ -1186,18 +1187,6 @@ memoize(Node, [
|
||||
'validate'
|
||||
])
|
||||
|
||||
/**
|
||||
* Normalize a `key`, from a key string or a node.
|
||||
*
|
||||
* @param {String or Node} key
|
||||
* @return {String} key
|
||||
*/
|
||||
|
||||
function normalizeKey(key) {
|
||||
if (typeof key == 'string') return key
|
||||
return key.key
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
@@ -1,5 +1,6 @@
|
||||
|
||||
import normalizeMark from '../utils/normalize-mark'
|
||||
import Normalize from '../utils/normalize'
|
||||
|
||||
import {
|
||||
addMarkAtRange,
|
||||
deleteAtRange,
|
||||
@@ -32,7 +33,7 @@ import {
|
||||
*/
|
||||
|
||||
export function addMark(state, mark) {
|
||||
mark = normalizeMark(mark)
|
||||
mark = Normalize.mark(mark)
|
||||
let { cursorMarks, document, selection } = state
|
||||
|
||||
// If the selection is collapsed, add the mark to the cursor instead.
|
||||
@@ -463,7 +464,7 @@ export function splitInline(state, depth = Infinity) {
|
||||
*/
|
||||
|
||||
export function removeMark(state, mark) {
|
||||
mark = normalizeMark(mark)
|
||||
mark = Normalize.mark(mark)
|
||||
let { cursorMarks, document, selection } = state
|
||||
|
||||
// If the selection is collapsed, remove the mark from the cursor instead.
|
||||
@@ -486,7 +487,7 @@ export function removeMark(state, mark) {
|
||||
*/
|
||||
|
||||
export function toggleMark(state, mark) {
|
||||
mark = normalizeMark(mark)
|
||||
mark = Normalize.mark(mark)
|
||||
const exists = state.marks.some(m => m.equals(mark))
|
||||
return exists
|
||||
? removeMark(state, mark)
|
||||
|
@@ -1,13 +1,10 @@
|
||||
|
||||
import Block from '../models/block'
|
||||
import Inline from '../models/inline'
|
||||
import Normalize from '../utils/normalize'
|
||||
import Selection from '../models/selection'
|
||||
import Text from '../models/text'
|
||||
import isInRange from '../utils/is-in-range'
|
||||
import normalizeBlock from '../utils/normalize-block'
|
||||
import normalizeInline from '../utils/normalize-inline'
|
||||
import normalizeMark from '../utils/normalize-mark'
|
||||
import normalizeProperties from '../utils/normalize-node-or-mark-properties'
|
||||
import uid from '../utils/uid'
|
||||
import { Set } from 'immutable'
|
||||
|
||||
@@ -24,7 +21,7 @@ export function addMarkAtRange(state, range, mark) {
|
||||
let { document } = state
|
||||
|
||||
// Normalize the mark.
|
||||
mark = normalizeMark(mark)
|
||||
mark = Normalize.mark(mark)
|
||||
|
||||
// When the range is collapsed, do nothing.
|
||||
if (range.isCollapsed) return state
|
||||
@@ -276,7 +273,7 @@ export function insertBlockAtRange(state, range, block) {
|
||||
let { document } = state
|
||||
|
||||
// Normalize the block argument.
|
||||
block = normalizeBlock(block)
|
||||
block = Normalize.block(block)
|
||||
|
||||
// If expanded, delete the range first.
|
||||
if (range.isExpanded) {
|
||||
@@ -460,7 +457,7 @@ export function insertInlineAtRange(state, range, inline) {
|
||||
let { document } = state
|
||||
|
||||
// Normalize the inline argument.
|
||||
inline = normalizeInline(inline)
|
||||
inline = Normalize.inline(inline)
|
||||
|
||||
// If expanded, delete the range first.
|
||||
if (range.isExpanded) {
|
||||
@@ -542,7 +539,7 @@ export function insertTextAtRange(state, range, string, marks) {
|
||||
*/
|
||||
|
||||
export function removeMarkAtRange(state, range, mark) {
|
||||
mark = normalizeMark(mark)
|
||||
mark = Normalize.mark(mark)
|
||||
let { document } = state
|
||||
|
||||
// When the range is collapsed, do nothing.
|
||||
@@ -584,7 +581,7 @@ export function removeMarkAtRange(state, range, mark) {
|
||||
*/
|
||||
|
||||
export function setBlockAtRange(state, range, properties = {}) {
|
||||
properties = normalizeProperties(properties)
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
const blocks = document.getBlocksAtRange(range)
|
||||
|
||||
@@ -608,7 +605,7 @@ export function setBlockAtRange(state, range, properties = {}) {
|
||||
*/
|
||||
|
||||
export function setInlineAtRange(state, range, properties = {}) {
|
||||
properties = normalizeProperties(properties)
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
const inlines = document.getInlinesAtRange(range)
|
||||
|
||||
@@ -801,7 +798,7 @@ export function splitTextAtRange(state, range) {
|
||||
*/
|
||||
|
||||
export function toggleMarkAtRange(state, range, mark) {
|
||||
mark = normalizeMark(mark)
|
||||
mark = Normalize.mark(mark)
|
||||
let { document } = state
|
||||
|
||||
// When the range is collapsed, do nothing.
|
||||
@@ -826,7 +823,7 @@ export function toggleMarkAtRange(state, range, mark) {
|
||||
*/
|
||||
|
||||
export function unwrapBlockAtRange(state, range, properties) {
|
||||
properties = normalizeProperties(properties)
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
|
||||
// Get the deepest blocks in the range.
|
||||
@@ -921,7 +918,7 @@ export function unwrapBlockAtRange(state, range, properties) {
|
||||
*/
|
||||
|
||||
export function unwrapInlineAtRange(state, range, properties) {
|
||||
properties = normalizeProperties(properties)
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
let blocks = document.getInlinesAtRange(range)
|
||||
|
||||
@@ -969,7 +966,7 @@ export function unwrapInlineAtRange(state, range, properties) {
|
||||
*/
|
||||
|
||||
export function wrapBlockAtRange(state, range, properties) {
|
||||
properties = normalizeProperties(properties)
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
|
||||
// Get the block nodes, sorted by depth.
|
||||
@@ -1028,7 +1025,7 @@ export function wrapBlockAtRange(state, range, properties) {
|
||||
*/
|
||||
|
||||
export function wrapInlineAtRange(state, range, properties) {
|
||||
properties = normalizeProperties(properties)
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
|
||||
// If collapsed, there's nothing to wrap.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
|
||||
import normalizeProperties from '../utils/normalize-node-or-mark-properties'
|
||||
import Normalize from '../utils/normalize'
|
||||
|
||||
/**
|
||||
* Remove a node by `key`.
|
||||
@@ -27,7 +27,7 @@ export function removeNodeByKey(state, key) {
|
||||
*/
|
||||
|
||||
export function setNodeByKey(state, key, properties) {
|
||||
properties = normalizeProperties(properties)
|
||||
properties = Normalize.nodeProperties(properties)
|
||||
let { document } = state
|
||||
let descendant = document.assertDescendant(key)
|
||||
descendant = descendant.merge(properties)
|
||||
|
@@ -1,35 +0,0 @@
|
||||
|
||||
import Block from '../models/block'
|
||||
import normalizeProperties from './normalize-node-or-mark-properties'
|
||||
import typeOf from 'type-of'
|
||||
|
||||
/**
|
||||
* Normalize a `block` argument, which can be a string or plain object too.
|
||||
*
|
||||
* @param {Block or String or Object} block
|
||||
* @return {Block}
|
||||
*/
|
||||
|
||||
function normalizeBlock(block) {
|
||||
if (block instanceof Block) return block
|
||||
|
||||
const type = typeOf(block)
|
||||
|
||||
switch (type) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Block.create(normalizeProperties(block))
|
||||
}
|
||||
default: {
|
||||
throw new Error(`A \`block\` argument must be a block, an object or a string, but you passed: "${type}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
export default normalizeBlock
|
@@ -1,35 +0,0 @@
|
||||
|
||||
import Inline from '../models/inline'
|
||||
import normalizeProperties from './normalize-node-or-mark-properties'
|
||||
import typeOf from 'type-of'
|
||||
|
||||
/**
|
||||
* Normalize an `inline` argument, which can be a string or plain object too.
|
||||
*
|
||||
* @param {Inline or String or Object} inline
|
||||
* @return {Inline}
|
||||
*/
|
||||
|
||||
function normalizeInline(inline) {
|
||||
if (inline instanceof Inline) return inline
|
||||
|
||||
const type = typeOf(inline)
|
||||
|
||||
switch (type) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Inline.create(normalizeProperties(inline))
|
||||
}
|
||||
default: {
|
||||
throw new Error(`An \`inline\` argument must be an inline, an object or a string, but you passed: "${type}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
export default normalizeInline
|
@@ -1,35 +0,0 @@
|
||||
|
||||
import Mark from '../models/mark'
|
||||
import typeOf from 'type-of'
|
||||
import normalizeProperties from './normalize-node-or-mark-properties'
|
||||
|
||||
/**
|
||||
* Normalize a `mark` argument, which can be a string or plain object too.
|
||||
*
|
||||
* @param {Mark or String or Object} mark
|
||||
* @return {Mark}
|
||||
*/
|
||||
|
||||
function normalizeMark(mark) {
|
||||
if (mark instanceof Mark) return mark
|
||||
|
||||
const type = typeOf(mark)
|
||||
|
||||
switch (type) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Mark.create(normalizeProperties(mark))
|
||||
}
|
||||
default: {
|
||||
throw new Error(`A \`mark\` argument must be a mark, an object or a string, but you passed: "${type}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
export default normalizeMark
|
@@ -1,47 +0,0 @@
|
||||
|
||||
import Data from '../models/data'
|
||||
import typeOf from 'type-of'
|
||||
|
||||
/**
|
||||
* Normalize the `properties` of a node or mark, which can be either a type
|
||||
* string or a dictionary of properties. If it's a dictionary, `data` is
|
||||
* optional and shouldn't be set if null or undefined.
|
||||
*
|
||||
* @param {String or Object} properties
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
function normalizeNodeOrMarkProperties(properties = {}) {
|
||||
const ret = {}
|
||||
const type = typeOf(properties)
|
||||
|
||||
switch (type) {
|
||||
case 'string': {
|
||||
ret.type = properties
|
||||
break
|
||||
}
|
||||
case 'object': {
|
||||
for (const key in properties) {
|
||||
if (key == 'data') {
|
||||
if (properties[key] != null) ret[key] = Data.create(properties[key])
|
||||
} else {
|
||||
ret[key] = properties[key]
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
default: {
|
||||
throw new Error(`A \`properties\` argument must be an object or a string, but you passed: "${type}".`)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
export default normalizeNodeOrMarkProperties
|
180
lib/utils/normalize.js
Normal file
180
lib/utils/normalize.js
Normal file
@@ -0,0 +1,180 @@
|
||||
|
||||
import Block from '../models/block'
|
||||
import Document from '../models/document'
|
||||
import Inline from '../models/inline'
|
||||
import Data from '../models/data'
|
||||
import Mark from '../models/mark'
|
||||
import Text from '../models/text'
|
||||
import typeOf from 'type-of'
|
||||
|
||||
/**
|
||||
* Normalize a block argument `value`.
|
||||
*
|
||||
* @param {Block || String || Object} value
|
||||
* @return {Block}
|
||||
*/
|
||||
|
||||
function block(value) {
|
||||
if (value instanceof Block) return value
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Block.create(nodeProperties(value))
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid \`block\` argument! It must be a block, an object, or a string. You passed: "${value}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize an inline argument `value`.
|
||||
*
|
||||
* @param {Inline || String || Object} value
|
||||
* @return {Inline}
|
||||
*/
|
||||
|
||||
function inline(value) {
|
||||
if (value instanceof Inline) return value
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Inline.create(nodeProperties(value))
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid \`inline\` argument! It must be an inline, an object, or a string. You passed: "${value}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a key argument `value`.
|
||||
*
|
||||
* @param {String || Node} value
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
function key(value) {
|
||||
if (value instanceof Block) return value.key
|
||||
if (value instanceof Inline) return value.key
|
||||
if (value instanceof Text) return value.key
|
||||
|
||||
// Special-case document for now.
|
||||
if (value instanceof Document) return
|
||||
|
||||
const type = typeOf(value)
|
||||
if (type == 'string') return value
|
||||
|
||||
throw new Error(`Invalid \`key\` argument! It must be either a block, an inline, a text, or a string. You passed: "${value}".`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a mark argument `value`.
|
||||
*
|
||||
* @param {Mark || String || Object} mark
|
||||
* @return {Mark}
|
||||
*/
|
||||
|
||||
function mark(value) {
|
||||
if (value instanceof Mark) return value
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
case 'string':
|
||||
case 'object': {
|
||||
return Mark.create(markProperties(value))
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid \`mark\` argument! It must be a mark, an object, or a string. You passed: "${value}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a mark properties argument `value`.
|
||||
*
|
||||
* @param {String || Object} value
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
function markProperties(value = {}) {
|
||||
const ret = {}
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
case 'string': {
|
||||
ret.type = value
|
||||
break
|
||||
}
|
||||
case 'object': {
|
||||
for (const k in value) {
|
||||
if (k == 'data') {
|
||||
if (value[k] != null) ret[k] = Data.create(value[k])
|
||||
} else {
|
||||
ret[k] = value[k]
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid mark \`properties\` argument! It must be an object or a string. You passed: "${value}".`)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a node properties argument `value`.
|
||||
*
|
||||
* @param {String || Object} value
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
function nodeProperties(value = {}) {
|
||||
const ret = {}
|
||||
const type = typeOf(value)
|
||||
|
||||
switch (type) {
|
||||
case 'string': {
|
||||
ret.type = value
|
||||
break
|
||||
}
|
||||
case 'object': {
|
||||
if (value.isVoid != null) ret.isVoid = !!value.isVoid
|
||||
for (const k in value) {
|
||||
if (k == 'data') {
|
||||
if (value[k] != null) ret[k] = Data.create(value[k])
|
||||
} else {
|
||||
ret[k] = value[k]
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid node \`properties\` argument! It must be an object or a string. You passed: "${value}".`)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
export default {
|
||||
block,
|
||||
inline,
|
||||
key,
|
||||
mark,
|
||||
markProperties,
|
||||
nodeProperties,
|
||||
}
|
||||
|
Reference in New Issue
Block a user