mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-09-01 19:22:35 +02:00
remove leaves (#2715)
* first stab at removing leaves with tests passing * add deprecation warning for creating texts with leaves * fixes * update examples
This commit is contained in:
@@ -27,12 +27,8 @@ const TEXT_RULE = {
|
||||
if (el.tagName && el.tagName.toLowerCase() === 'br') {
|
||||
return {
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '\n',
|
||||
},
|
||||
],
|
||||
text: '\n',
|
||||
marks: [],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,12 +37,8 @@ const TEXT_RULE = {
|
||||
|
||||
return {
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: el.nodeValue,
|
||||
},
|
||||
],
|
||||
text: el.nodeValue,
|
||||
marks: [],
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -162,13 +154,8 @@ class Html {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -274,6 +261,14 @@ class Html {
|
||||
node = ret
|
||||
}
|
||||
|
||||
if (node.object === 'block' || node.object === 'inline') {
|
||||
node.data = node.data || {}
|
||||
node.nodes = node.nodes || []
|
||||
} else if (node.object === 'text') {
|
||||
node.marks = node.marks || []
|
||||
node.text = node.text || ''
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
@@ -292,13 +287,11 @@ class Html {
|
||||
|
||||
const applyMark = node => {
|
||||
if (node.object === 'mark') {
|
||||
return this.deserializeMark(node)
|
||||
const ret = this.deserializeMark(node)
|
||||
return ret
|
||||
} else if (node.object === 'text') {
|
||||
node.leaves = node.leaves.map(leaf => {
|
||||
leaf.marks = leaf.marks || []
|
||||
leaf.marks.push({ type, data })
|
||||
return leaf
|
||||
})
|
||||
node.marks = node.marks || []
|
||||
node.marks.push({ type, data })
|
||||
} else if (node.nodes) {
|
||||
node.nodes = node.nodes.map(applyMark)
|
||||
}
|
||||
|
@@ -43,12 +43,8 @@ export const output = (
|
||||
<document>
|
||||
<paragraph>
|
||||
<text>o</text>
|
||||
<text>
|
||||
<b>n</b>
|
||||
</text>
|
||||
<text>
|
||||
<b>e</b>
|
||||
</text>
|
||||
<b>n</b>
|
||||
<b>e</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -29,15 +29,12 @@ export const output = {
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
Decoration,
|
||||
Document,
|
||||
Leaf,
|
||||
Mark,
|
||||
Node,
|
||||
Point,
|
||||
@@ -42,7 +41,7 @@ export function createAnchor(tagName, attributes, children) {
|
||||
|
||||
export function createBlock(tagName, attributes, children) {
|
||||
const attrs = { ...attributes, object: 'block' }
|
||||
const block = createNode('node', attrs, children)
|
||||
const block = createNode(null, attrs, children)
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -77,15 +76,15 @@ export function createDecoration(tagName, attributes, children) {
|
||||
return new DecorationPoint({ id: key, type, data })
|
||||
}
|
||||
|
||||
const leaves = createLeaves('leaves', {}, children)
|
||||
const first = leaves.first()
|
||||
const last = leaves.last()
|
||||
const texts = createChildren(children)
|
||||
const first = texts.first()
|
||||
const last = texts.last()
|
||||
const id = `__decoration_${uid++}__`
|
||||
const start = new DecorationPoint({ id, type, data })
|
||||
const end = new DecorationPoint({ id, type, data })
|
||||
setPoint(first, start, 0)
|
||||
setPoint(last, end, last.text.length)
|
||||
return leaves
|
||||
return texts
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +98,7 @@ export function createDecoration(tagName, attributes, children) {
|
||||
|
||||
export function createDocument(tagName, attributes, children) {
|
||||
const attrs = { ...attributes, object: 'document' }
|
||||
const document = createNode('node', attrs, children)
|
||||
const document = createNode(null, attrs, children)
|
||||
return document
|
||||
}
|
||||
|
||||
@@ -127,65 +126,10 @@ export function createFocus(tagName, attributes, children) {
|
||||
|
||||
export function createInline(tagName, attributes, children) {
|
||||
const attrs = { ...attributes, object: 'inline' }
|
||||
const inline = createNode('node', attrs, children)
|
||||
const inline = createNode(null, attrs, children)
|
||||
return inline
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of leaves.
|
||||
*
|
||||
* @param {String} tagName
|
||||
* @param {Object} attributes
|
||||
* @param {Array} children
|
||||
* @return {List<Leaf>}
|
||||
*/
|
||||
|
||||
export function createLeaves(tagName, attributes, children) {
|
||||
const { marks = Mark.createSet() } = attributes
|
||||
let length = 0
|
||||
let leaves = Leaf.createList([])
|
||||
let leaf
|
||||
|
||||
children.forEach(child => {
|
||||
if (Leaf.isLeafList(child)) {
|
||||
if (leaf) {
|
||||
leaves = leaves.push(leaf)
|
||||
leaf = null
|
||||
}
|
||||
|
||||
child.forEach(l => {
|
||||
l = preservePoint(l, obj => obj.addMarks(marks))
|
||||
leaves = leaves.push(l)
|
||||
})
|
||||
} else {
|
||||
if (!leaf) {
|
||||
leaf = Leaf.create({ marks, text: '' })
|
||||
length = 0
|
||||
}
|
||||
|
||||
if (typeof child === 'string') {
|
||||
const offset = leaf.text.length
|
||||
leaf = preservePoint(leaf, obj => obj.insertText(offset, child))
|
||||
length += child.length
|
||||
}
|
||||
|
||||
if (isPoint(child)) {
|
||||
setPoint(leaf, child, length)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!leaves.size && !leaf) {
|
||||
leaf = Leaf.create({ marks, text: '' })
|
||||
}
|
||||
|
||||
if (leaf) {
|
||||
leaves = leaves.push(leaf)
|
||||
}
|
||||
|
||||
return leaves
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of leaves from a mark.
|
||||
*
|
||||
@@ -196,9 +140,28 @@ export function createLeaves(tagName, attributes, children) {
|
||||
*/
|
||||
|
||||
export function createMark(tagName, attributes, children) {
|
||||
const marks = Mark.createSet([attributes])
|
||||
const leaves = createLeaves('leaves', { marks }, children)
|
||||
return leaves
|
||||
const { key, ...mark } = attributes
|
||||
const marks = Mark.createSet([mark])
|
||||
const list = createChildren(children)
|
||||
let node
|
||||
|
||||
if (list.size > 1) {
|
||||
throw new Error(
|
||||
`The <mark> hyperscript tag must only contain a single node's worth of children.`
|
||||
)
|
||||
} else if (list.size === 0) {
|
||||
node = Text.create({ key, marks })
|
||||
} else {
|
||||
node = list.first()
|
||||
|
||||
node = preservePoints(node, n => {
|
||||
if (key) n = n.set('key', key)
|
||||
if (marks) n = n.set('marks', n.marks.union(marks))
|
||||
return n
|
||||
})
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,31 +177,11 @@ export function createNode(tagName, attributes, children) {
|
||||
const { object } = attributes
|
||||
|
||||
if (object === 'text') {
|
||||
return createText('text', {}, children)
|
||||
}
|
||||
|
||||
const nodes = []
|
||||
let others = []
|
||||
|
||||
children.forEach(child => {
|
||||
if (Node.isNode(child)) {
|
||||
if (others.length) {
|
||||
const text = createText('text', {}, others)
|
||||
nodes.push(text)
|
||||
}
|
||||
|
||||
nodes.push(child)
|
||||
others = []
|
||||
} else {
|
||||
others.push(child)
|
||||
}
|
||||
})
|
||||
|
||||
if (others.length) {
|
||||
const text = createText('text', {}, others)
|
||||
nodes.push(text)
|
||||
const text = createText(null, attributes, children)
|
||||
return text
|
||||
}
|
||||
|
||||
const nodes = createChildren(children)
|
||||
const node = Node.create({ ...attributes, nodes })
|
||||
return node
|
||||
}
|
||||
@@ -284,18 +227,27 @@ export function createSelection(tagName, attributes, children) {
|
||||
*/
|
||||
|
||||
export function createText(tagName, attributes, children) {
|
||||
const { key } = attributes
|
||||
const leaves = createLeaves('leaves', {}, children)
|
||||
const text = Text.create({ key, leaves })
|
||||
let length = 0
|
||||
const { key, marks } = attributes
|
||||
const list = createChildren(children)
|
||||
let node
|
||||
|
||||
leaves.forEach(leaf => {
|
||||
incrementPoint(leaf, length)
|
||||
preservePoint(leaf, () => text)
|
||||
length += leaf.text.length
|
||||
})
|
||||
if (list.size > 1) {
|
||||
throw new Error(
|
||||
`The <text> hyperscript tag must only contain a single node's worth of children.`
|
||||
)
|
||||
} else if (list.size === 0) {
|
||||
node = Text.create({ key })
|
||||
} else {
|
||||
node = list.first()
|
||||
|
||||
return text
|
||||
node = preservePoints(node, n => {
|
||||
if (key) n = n.set('key', key)
|
||||
if (marks) n = n.set('marks', Mark.createSet(marks))
|
||||
return n
|
||||
})
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,6 +366,74 @@ export function createValue(tagName, attributes, children) {
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of text nodes.
|
||||
*
|
||||
* @param {Array} children
|
||||
* @return {List<Leaf>}
|
||||
*/
|
||||
|
||||
export function createChildren(children) {
|
||||
let nodes = Node.createList()
|
||||
|
||||
const push = node => {
|
||||
const last = nodes.last()
|
||||
const isString = typeof node === 'string'
|
||||
|
||||
if (last && last.__string && (isString || node.__string)) {
|
||||
const text = isString ? node : node.text
|
||||
const { length } = last.text
|
||||
const next = preservePoints(last, l => l.insertText(length, text))
|
||||
incrementPoints(node, length)
|
||||
copyPoints(node, next)
|
||||
next.__string = true
|
||||
nodes = nodes.pop().push(next)
|
||||
} else if (isString) {
|
||||
node = Text.create({ text: node })
|
||||
node.__string = true
|
||||
nodes = nodes.push(node)
|
||||
} else {
|
||||
nodes = nodes.push(node)
|
||||
}
|
||||
}
|
||||
|
||||
children.forEach(child => {
|
||||
if (Node.isNodeList(child)) {
|
||||
child.forEach(c => push(c))
|
||||
}
|
||||
|
||||
if (Node.isNode(child)) {
|
||||
push(child)
|
||||
}
|
||||
|
||||
if (typeof child === 'string') {
|
||||
push(child)
|
||||
}
|
||||
|
||||
if (isPoint(child)) {
|
||||
if (!nodes.size) {
|
||||
push('')
|
||||
}
|
||||
|
||||
let last = nodes.last()
|
||||
|
||||
if (last.object !== 'text') {
|
||||
push('')
|
||||
last = nodes.last()
|
||||
}
|
||||
|
||||
if (!last || !last.__string) {
|
||||
push('')
|
||||
last = nodes.last()
|
||||
}
|
||||
|
||||
setPoint(last, child, last.text.length)
|
||||
}
|
||||
})
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
/**
|
||||
* Point classes that can be created at different points in the document and
|
||||
* then searched for afterwards, for creating ranges.
|
||||
@@ -481,7 +501,7 @@ class DecorationPoint {
|
||||
* @param {Number} n
|
||||
*/
|
||||
|
||||
function incrementPoint(object, n) {
|
||||
function incrementPoints(object, n) {
|
||||
const { __anchor, __focus, __decorations } = object
|
||||
|
||||
if (__anchor != null) {
|
||||
@@ -521,15 +541,19 @@ function isPoint(object) {
|
||||
* @return {Any}
|
||||
*/
|
||||
|
||||
function preservePoint(object, updator) {
|
||||
const { __anchor, __focus, __decorations } = object
|
||||
function preservePoints(object, updator) {
|
||||
const next = updator(object)
|
||||
if (__anchor != null) next.__anchor = __anchor
|
||||
if (__focus != null) next.__focus = __focus
|
||||
if (__decorations != null) next.__decorations = __decorations
|
||||
copyPoints(object, next)
|
||||
return next
|
||||
}
|
||||
|
||||
function copyPoints(object, other) {
|
||||
const { __anchor, __focus, __decorations } = object
|
||||
if (__anchor != null) other.__anchor = __anchor
|
||||
if (__focus != null) other.__focus = __focus
|
||||
if (__decorations != null) other.__decorations = __decorations
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a `point` on an `object`.
|
||||
*
|
||||
|
@@ -20,13 +20,8 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -15,17 +15,12 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
text: '',
|
||||
marks: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -15,17 +15,12 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
text: 'word',
|
||||
marks: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
44
packages/slate-hyperscript/test/fixtures/block-mark-multiple.js
vendored
Normal file
44
packages/slate-hyperscript/test/fixtures/block-mark-multiple.js
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<block type="paragraph">
|
||||
<mark type="bold">one</mark>two<mark type="italic">three</mark>
|
||||
</block>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
text: 'one',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: 'three',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'italic',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -4,9 +4,11 @@ import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<block type="paragraph">
|
||||
<mark type="bold">w</mark>
|
||||
<mark type="bold">
|
||||
w<mark type="italic">or</mark>d
|
||||
<mark type="italic">or</mark>
|
||||
</mark>
|
||||
<mark type="bold">d</mark>
|
||||
</block>
|
||||
)
|
||||
|
||||
@@ -17,44 +19,39 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
text: 'w',
|
||||
marks: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'w',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: 'or',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'italic',
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'or',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'italic',
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: 'd',
|
||||
marks: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'd',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -11,13 +11,8 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@@ -15,13 +15,8 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@@ -15,13 +15,8 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@@ -33,13 +33,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -44,13 +44,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
@@ -61,26 +56,16 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '1',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '3',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -93,13 +78,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '5',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
@@ -110,26 +90,16 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '6',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '8',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -36,13 +36,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -55,13 +50,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -36,13 +36,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -55,13 +50,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -36,13 +36,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -55,13 +50,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
81
packages/slate-hyperscript/test/fixtures/cursor-across-empty-blocks.js
vendored
Normal file
81
packages/slate-hyperscript/test/fixtures/cursor-across-empty-blocks.js
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
<text>
|
||||
<anchor />
|
||||
</text>
|
||||
</block>
|
||||
<block type="paragraph">
|
||||
<text>
|
||||
<focus />
|
||||
</text>
|
||||
</block>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const options = {
|
||||
preserveSelection: true,
|
||||
preserveKeys: true,
|
||||
}
|
||||
|
||||
export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '4',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '1',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'block',
|
||||
key: '3',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
selection: {
|
||||
object: 'selection',
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 0,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: '2',
|
||||
path: [1, 0],
|
||||
offset: 0,
|
||||
},
|
||||
isFocused: true,
|
||||
marks: null,
|
||||
},
|
||||
}
|
@@ -37,13 +37,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -56,13 +51,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -75,13 +65,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '4',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -37,13 +37,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -56,13 +51,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -75,13 +65,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '4',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -37,13 +37,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -56,13 +51,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -75,13 +65,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '4',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -33,13 +33,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -33,13 +33,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -33,13 +33,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -39,13 +39,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
62
packages/slate-hyperscript/test/fixtures/cursor-empty-text-with-key.js
vendored
Normal file
62
packages/slate-hyperscript/test/fixtures/cursor-empty-text-with-key.js
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
<text key="a">
|
||||
<cursor />
|
||||
</text>
|
||||
</block>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const options = {
|
||||
preserveSelection: true,
|
||||
preserveKeys: true,
|
||||
}
|
||||
|
||||
export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '1',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: 'a',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
selection: {
|
||||
object: 'selection',
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: 'a',
|
||||
path: [0, 0],
|
||||
offset: 0,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: 'a',
|
||||
path: [0, 0],
|
||||
offset: 0,
|
||||
},
|
||||
isFocused: true,
|
||||
marks: null,
|
||||
},
|
||||
}
|
62
packages/slate-hyperscript/test/fixtures/cursor-empty-text.js
vendored
Normal file
62
packages/slate-hyperscript/test/fixtures/cursor-empty-text.js
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
<text>
|
||||
<cursor />
|
||||
</text>
|
||||
</block>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const options = {
|
||||
preserveSelection: true,
|
||||
preserveKeys: true,
|
||||
}
|
||||
|
||||
export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '1',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
selection: {
|
||||
object: 'selection',
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 0,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 0,
|
||||
},
|
||||
isFocused: true,
|
||||
marks: null,
|
||||
},
|
||||
}
|
@@ -37,13 +37,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
@@ -54,26 +49,16 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '3',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -37,13 +37,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
@@ -54,26 +49,16 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '3',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -37,13 +37,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
@@ -54,26 +49,16 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '3',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -33,13 +33,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
73
packages/slate-hyperscript/test/fixtures/cursor-mark-after.js
vendored
Normal file
73
packages/slate-hyperscript/test/fixtures/cursor-mark-after.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<block type="paragraph">
|
||||
<mark type="bold">one</mark>
|
||||
<cursor />two
|
||||
</block>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const options = {
|
||||
preserveSelection: true,
|
||||
preserveKeys: true,
|
||||
}
|
||||
|
||||
export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '3',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '2',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
text: 'one',
|
||||
key: '0',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '1',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
selection: {
|
||||
object: 'selection',
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: '1',
|
||||
path: [0, 1],
|
||||
offset: 0,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: '1',
|
||||
path: [0, 1],
|
||||
offset: 0,
|
||||
},
|
||||
isFocused: true,
|
||||
marks: null,
|
||||
},
|
||||
}
|
@@ -26,41 +26,38 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '2',
|
||||
key: '4',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '1',
|
||||
key: '3',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '1',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: 'two',
|
||||
key: '0',
|
||||
leaves: [
|
||||
marks: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -70,14 +67,14 @@ export const output = {
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 6,
|
||||
path: [0, 1],
|
||||
offset: 3,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 6,
|
||||
path: [0, 1],
|
||||
offset: 3,
|
||||
},
|
||||
isFocused: true,
|
||||
marks: null,
|
||||
|
@@ -26,41 +26,38 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '2',
|
||||
key: '4',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '1',
|
||||
key: '3',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '1',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
text: 'two',
|
||||
marks: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -70,14 +67,14 @@ export const output = {
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 3,
|
||||
path: [0, 1],
|
||||
offset: 0,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 3,
|
||||
path: [0, 1],
|
||||
offset: 0,
|
||||
},
|
||||
isFocused: true,
|
||||
marks: null,
|
||||
|
@@ -26,41 +26,38 @@ export const output = {
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
key: '2',
|
||||
key: '4',
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '1',
|
||||
key: '3',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '1',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
text: 'two',
|
||||
marks: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
text: 'three',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -70,14 +67,14 @@ export const output = {
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 4,
|
||||
path: [0, 1],
|
||||
offset: 1,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
path: [0, 0],
|
||||
offset: 4,
|
||||
path: [0, 1],
|
||||
offset: 1,
|
||||
},
|
||||
isFocused: true,
|
||||
marks: null,
|
||||
|
@@ -33,13 +33,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
68
packages/slate-hyperscript/test/fixtures/custom-marks-with-text.js
vendored
Normal file
68
packages/slate-hyperscript/test/fixtures/custom-marks-with-text.js
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/** @jsx h */
|
||||
|
||||
import { createHyperscript } from 'slate-hyperscript'
|
||||
|
||||
const h = createHyperscript({
|
||||
blocks: {
|
||||
paragraph: 'paragraph',
|
||||
},
|
||||
marks: {
|
||||
b: 'bold',
|
||||
},
|
||||
})
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<text>one</text>
|
||||
<b>two</b>
|
||||
<b>three</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: 'two',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: 'three',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
@@ -40,30 +40,25 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
text: 'A string of ',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: 'bold',
|
||||
marks: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'A string of ',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'bold',
|
||||
marks: [
|
||||
{
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' in a ',
|
||||
marks: [],
|
||||
object: 'mark',
|
||||
type: 'bold',
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
text: ' in a ',
|
||||
marks: [],
|
||||
},
|
||||
{
|
||||
object: 'inline',
|
||||
type: 'link',
|
||||
@@ -73,25 +68,15 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'Slate',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'Slate',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: ' editor!',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: ' editor!',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -30,25 +30,20 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '2',
|
||||
key: '3',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '1',
|
||||
key: '2',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'onetwothree',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
key: '1',
|
||||
text: 'onetwothree',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -59,13 +54,13 @@ export const output = {
|
||||
object: 'decoration',
|
||||
anchor: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
key: '1',
|
||||
path: [0, 0],
|
||||
offset: 3,
|
||||
},
|
||||
focus: {
|
||||
object: 'point',
|
||||
key: '0',
|
||||
key: '1',
|
||||
path: [0, 0],
|
||||
offset: 6,
|
||||
},
|
||||
|
@@ -45,13 +45,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '0',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -64,13 +59,8 @@ export const output = {
|
||||
{
|
||||
object: 'text',
|
||||
key: '2',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -11,13 +11,8 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@@ -25,25 +25,20 @@ export const output = {
|
||||
object: 'value',
|
||||
document: {
|
||||
object: 'document',
|
||||
key: '1',
|
||||
key: '2',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'block',
|
||||
key: '0',
|
||||
key: '1',
|
||||
type: 'paragraph',
|
||||
data: {},
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
key: 'a',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'two',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -6,11 +6,6 @@ export const input = <text />
|
||||
|
||||
export const output = {
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: '',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: '',
|
||||
marks: [],
|
||||
}
|
||||
|
@@ -6,11 +6,6 @@ export const input = <text>word</text>
|
||||
|
||||
export const output = {
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'word',
|
||||
marks: [],
|
||||
}
|
||||
|
15
packages/slate-hyperscript/test/fixtures/text-nested.js
vendored
Normal file
15
packages/slate-hyperscript/test/fixtures/text-nested.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from 'slate-hyperscript'
|
||||
|
||||
export const input = (
|
||||
<text>
|
||||
<text>word</text>
|
||||
</text>
|
||||
)
|
||||
|
||||
export const output = {
|
||||
object: 'text',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
}
|
@@ -11,11 +11,6 @@ export const options = {
|
||||
export const output = {
|
||||
object: 'text',
|
||||
key: 'a',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'word',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'word',
|
||||
marks: [],
|
||||
}
|
||||
|
@@ -40,13 +40,8 @@ function deserialize(string, options = {}) {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: line,
|
||||
marks: defaultMarks,
|
||||
},
|
||||
],
|
||||
text: line,
|
||||
marks: defaultMarks,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@@ -15,13 +15,8 @@ export const output = {
|
||||
nodes: [
|
||||
{
|
||||
object: 'text',
|
||||
leaves: [
|
||||
{
|
||||
object: 'leaf',
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
text: 'one',
|
||||
marks: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -36,7 +36,7 @@ export const value = (
|
||||
<document>
|
||||
<paragraph>
|
||||
<text key="a">
|
||||
<anchor />
|
||||
<anchor isFocused={false} />
|
||||
</text>
|
||||
</paragraph>
|
||||
<image src="https://example.com/image.png">
|
||||
@@ -44,17 +44,13 @@ export const value = (
|
||||
</image>
|
||||
<paragraph>
|
||||
<text key="b">
|
||||
<focus />
|
||||
<focus isFocused={false} />
|
||||
</text>
|
||||
</paragraph>
|
||||
<image src="https://example.com/image2.png">
|
||||
<text />
|
||||
</image>
|
||||
</document>
|
||||
<selection isFocused={false}>
|
||||
<anchor key="a" offset={0} />
|
||||
<focus key="b" offset={0} />
|
||||
</selection>
|
||||
</value>
|
||||
)
|
||||
|
||||
|
@@ -37,11 +37,15 @@ export const output = `
|
||||
<span data-slate-leaf="true">
|
||||
<span data-slate-content="true">one</span>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
<span data-slate-leaf="true">
|
||||
<strong data-slate-mark="true">
|
||||
<span data-slate-content="true">two</span>
|
||||
</strong>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
<span data-slate-leaf="true">
|
||||
<span data-slate-content="true">three</span>
|
||||
</span>
|
||||
|
@@ -865,7 +865,9 @@ Commands.insertInlineAtRange = (editor, range, inline) => {
|
||||
const startText = document.assertDescendant(start.key)
|
||||
const index = parent.nodes.indexOf(startText)
|
||||
|
||||
if (editor.isVoid(parent)) return
|
||||
if (editor.isVoid(parent)) {
|
||||
return
|
||||
}
|
||||
|
||||
editor.splitNodeByKey(start.key, start.offset)
|
||||
editor.insertNodeByKey(parent.key, index + 1, inline)
|
||||
@@ -1329,28 +1331,23 @@ Commands.wrapInlineAtRange = (editor, range, inline) => {
|
||||
const endIndex = endBlock.nodes.indexOf(endChild)
|
||||
|
||||
if (startInline && startInline === endInline) {
|
||||
const text = startBlock
|
||||
.getTextsAtRange(range)
|
||||
.get(0)
|
||||
.splitText(start.offset)[1]
|
||||
.splitText(end.offset - start.offset)[0]
|
||||
const texts = startBlock.getTextsAtRange(range).map(text => {
|
||||
if (start.key === text.key && end.key === text.key) {
|
||||
return text
|
||||
.splitText(start.offset)[1]
|
||||
.splitText(end.offset - start.offset)[0]
|
||||
.regenerateKey()
|
||||
} else if (start.key === text.key) {
|
||||
return text.splitText(start.offset)[1].regenerateKey()
|
||||
} else if (end.key === text.key) {
|
||||
return text.splitText(end.offset)[0].regenerateKey()
|
||||
} else {
|
||||
return text.regenerateKey()
|
||||
}
|
||||
})
|
||||
|
||||
inline = inline.set('nodes', List([text]))
|
||||
inline = inline.set('nodes', texts)
|
||||
editor.insertInlineAtRange(range, inline)
|
||||
|
||||
const inlinekey = inline.getFirstText().key
|
||||
const rng = {
|
||||
anchor: {
|
||||
key: inlinekey,
|
||||
offset: 0,
|
||||
},
|
||||
focus: {
|
||||
key: inlinekey,
|
||||
offset: end.offset - start.offset,
|
||||
},
|
||||
isFocused: true,
|
||||
}
|
||||
editor.select(rng)
|
||||
} else if (startBlock === endBlock) {
|
||||
document = editor.value.document
|
||||
startBlock = document.getClosestBlock(start.key)
|
||||
@@ -1422,8 +1419,8 @@ Commands.wrapTextAtRange = (editor, range, prefix, suffix = prefix) => {
|
||||
}
|
||||
|
||||
editor.withoutNormalizing(() => {
|
||||
editor.insertTextAtRange(startRange, prefix, [])
|
||||
editor.insertTextAtRange(endRange, suffix, [])
|
||||
editor.insertTextAtRange(startRange, prefix)
|
||||
editor.insertTextAtRange(endRange, suffix)
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -25,42 +25,43 @@ const Commands = {}
|
||||
|
||||
Commands.addMarkByPath = (editor, path, offset, length, mark) => {
|
||||
mark = Mark.create(mark)
|
||||
editor.addMarksByPath(path, offset, length, [mark])
|
||||
}
|
||||
|
||||
Commands.addMarksByPath = (editor, path, offset, length, marks) => {
|
||||
marks = Mark.createSet(marks)
|
||||
|
||||
if (!marks.size) {
|
||||
return
|
||||
}
|
||||
|
||||
const { value } = editor
|
||||
const { document } = value
|
||||
const node = document.assertNode(path)
|
||||
const leaves = node.getLeaves()
|
||||
|
||||
const operations = []
|
||||
const bx = offset
|
||||
const by = offset + length
|
||||
let o = 0
|
||||
editor.withoutNormalizing(() => {
|
||||
// If it ends before the end of the node, we'll need to split to create a new
|
||||
// text with different marks.
|
||||
if (offset + length < node.text.length) {
|
||||
editor.splitNodeByPath(path, offset + length)
|
||||
}
|
||||
|
||||
leaves.forEach(leaf => {
|
||||
const ax = o
|
||||
const ay = ax + leaf.text.length
|
||||
// Same thing if it starts after the start. But in that case, we need to
|
||||
// update our path and offset to point to the new start.
|
||||
if (offset > 0) {
|
||||
editor.splitNodeByPath(path, offset)
|
||||
path = PathUtils.increment(path)
|
||||
offset = 0
|
||||
}
|
||||
|
||||
o += leaf.text.length
|
||||
|
||||
// If the leaf doesn't overlap with the operation, continue on.
|
||||
if (ay < bx || by < ax) return
|
||||
|
||||
// If the leaf already has the mark, continue on.
|
||||
if (leaf.marks.has(mark)) return
|
||||
|
||||
// Otherwise, determine which offset and characters overlap.
|
||||
const start = Math.max(ax, bx)
|
||||
const end = Math.min(ay, by)
|
||||
|
||||
operations.push({
|
||||
type: 'add_mark',
|
||||
path,
|
||||
offset: start,
|
||||
length: end - start,
|
||||
mark,
|
||||
marks.forEach(mark => {
|
||||
editor.applyOperation({
|
||||
type: 'add_mark',
|
||||
path,
|
||||
mark: Mark.create(mark),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
operations.forEach(op => editor.applyOperation(op))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,13 +107,12 @@ Commands.insertNodeByPath = (editor, path, index, node) => {
|
||||
*/
|
||||
|
||||
Commands.insertTextByPath = (editor, path, offset, text, marks) => {
|
||||
marks = Mark.createSet(marks)
|
||||
const { value } = editor
|
||||
const { decorations, document } = value
|
||||
const node = document.assertNode(path)
|
||||
marks = marks || node.getMarksAtIndex(offset)
|
||||
|
||||
let updated = false
|
||||
const { key } = node
|
||||
let updated = false
|
||||
|
||||
const decs = decorations.filter(dec => {
|
||||
const { start, end, mark } = dec
|
||||
@@ -128,16 +128,21 @@ Commands.insertTextByPath = (editor, path, offset, text, marks) => {
|
||||
return true
|
||||
})
|
||||
|
||||
if (updated) {
|
||||
editor.setDecorations(decs)
|
||||
}
|
||||
editor.withoutNormalizing(() => {
|
||||
if (updated) {
|
||||
editor.setDecorations(decs)
|
||||
}
|
||||
|
||||
editor.applyOperation({
|
||||
type: 'insert_text',
|
||||
path,
|
||||
offset,
|
||||
text,
|
||||
marks,
|
||||
editor.applyOperation({
|
||||
type: 'insert_text',
|
||||
path,
|
||||
offset,
|
||||
text,
|
||||
})
|
||||
|
||||
if (marks.size) {
|
||||
editor.addMarksByPath(path, offset, text.length, marks)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -218,42 +223,45 @@ Commands.moveNodeByPath = (editor, path, newParentPath, newIndex) => {
|
||||
|
||||
Commands.removeMarkByPath = (editor, path, offset, length, mark) => {
|
||||
mark = Mark.create(mark)
|
||||
editor.removeMarksByPath(path, offset, length, [mark])
|
||||
}
|
||||
|
||||
Commands.removeMarksByPath = (editor, path, offset, length, marks) => {
|
||||
marks = Mark.createSet(marks)
|
||||
|
||||
if (!marks.size) {
|
||||
return
|
||||
}
|
||||
|
||||
const { value } = editor
|
||||
const { document } = value
|
||||
const node = document.assertNode(path)
|
||||
const leaves = node.getLeaves()
|
||||
|
||||
const operations = []
|
||||
const bx = offset
|
||||
const by = offset + length
|
||||
let o = 0
|
||||
editor.withoutNormalizing(() => {
|
||||
// If it ends before the end of the node, we'll need to split to create a new
|
||||
// text with different marks.
|
||||
if (offset + length < node.text.length) {
|
||||
editor.splitNodeByPath(path, offset + length)
|
||||
}
|
||||
|
||||
leaves.forEach(leaf => {
|
||||
const ax = o
|
||||
const ay = ax + leaf.text.length
|
||||
// Same thing if it starts after the start. But in that case, we need to
|
||||
// update our path and offset to point to the new start.
|
||||
if (offset > 0) {
|
||||
editor.splitNodeByPath(path, offset)
|
||||
path = PathUtils.increment(path)
|
||||
offset = 0
|
||||
}
|
||||
|
||||
o += leaf.text.length
|
||||
|
||||
// If the leaf doesn't overlap with the operation, continue on.
|
||||
if (ay < bx || by < ax) return
|
||||
|
||||
// If the leaf already has the mark, continue on.
|
||||
if (!leaf.marks.has(mark)) return
|
||||
|
||||
// Otherwise, determine which offset and characters overlap.
|
||||
const start = Math.max(ax, bx)
|
||||
const end = Math.min(ay, by)
|
||||
|
||||
operations.push({
|
||||
type: 'remove_mark',
|
||||
path,
|
||||
offset: start,
|
||||
length: end - start,
|
||||
mark,
|
||||
marks.forEach(mark => {
|
||||
editor.applyOperation({
|
||||
type: 'remove_mark',
|
||||
path,
|
||||
offset,
|
||||
length,
|
||||
mark,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
operations.forEach(op => editor.applyOperation(op))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,7 +278,7 @@ Commands.removeAllMarksByPath = (editor, path) => {
|
||||
const texts = node.object === 'text' ? [node] : node.getTextsAsArray()
|
||||
|
||||
texts.forEach(text => {
|
||||
text.getMarksAsArray().forEach(mark => {
|
||||
text.marks.forEach(mark => {
|
||||
editor.removeMarkByKey(text.key, 0, text.text.length, mark)
|
||||
})
|
||||
})
|
||||
@@ -306,69 +314,47 @@ Commands.removeNodeByPath = (editor, path) => {
|
||||
|
||||
Commands.removeTextByPath = (editor, path, offset, length) => {
|
||||
const { value } = editor
|
||||
const { decorations, document } = value
|
||||
const { document, decorations } = value
|
||||
const node = document.assertNode(path)
|
||||
const leaves = node.getLeaves()
|
||||
const { text } = node
|
||||
|
||||
let updated = false
|
||||
const { text } = node
|
||||
const string = text.slice(offset, offset + length)
|
||||
|
||||
const { key } = node
|
||||
const from = offset
|
||||
const to = offset + length
|
||||
let updated = false
|
||||
|
||||
const decs = decorations.filter(dec => {
|
||||
const { start, end, mark } = dec
|
||||
const isAtomic = editor.isAtomic(mark)
|
||||
if (!isAtomic) return true
|
||||
if (start.key !== key) return true
|
||||
|
||||
if (start.offset < from && (end.key !== key || end.offset > from)) {
|
||||
updated = true
|
||||
return false
|
||||
if (!isAtomic) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (start.offset < to && (end.key !== key || end.offset > to)) {
|
||||
if (start.key !== key) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (start.offset < offset && (end.key !== key || end.offset > offset)) {
|
||||
updated = true
|
||||
return null
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if (updated) {
|
||||
editor.setDecorations(decs)
|
||||
}
|
||||
editor.withoutNormalizing(() => {
|
||||
if (updated) {
|
||||
editor.setDecorations(decs)
|
||||
}
|
||||
|
||||
const removals = []
|
||||
const bx = offset
|
||||
const by = offset + length
|
||||
let o = 0
|
||||
|
||||
leaves.forEach(leaf => {
|
||||
const ax = o
|
||||
const ay = ax + leaf.text.length
|
||||
|
||||
o += leaf.text.length
|
||||
|
||||
// If the leaf doesn't overlap with the removal, continue on.
|
||||
if (ay < bx || by < ax) return
|
||||
|
||||
// Otherwise, determine which offset and characters overlap.
|
||||
const start = Math.max(ax, bx)
|
||||
const end = Math.min(ay, by)
|
||||
const string = text.slice(start, end)
|
||||
|
||||
removals.push({
|
||||
editor.applyOperation({
|
||||
type: 'remove_text',
|
||||
path,
|
||||
offset: start,
|
||||
offset,
|
||||
text: string,
|
||||
marks: leaf.marks,
|
||||
})
|
||||
})
|
||||
|
||||
// Apply in reverse order, so subsequent removals don't impact previous ones.
|
||||
removals.reverse().forEach(op => editor.applyOperation(op))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,7 +377,8 @@ Commands.replaceNodeByPath = (editor, path, newNode) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace A Length of Text with another string or text
|
||||
* Replace a `length` of text at `offset` with new `text` and optional `marks`.
|
||||
*
|
||||
* @param {Editor} editor
|
||||
* @param {String} key
|
||||
* @param {Number} offset
|
||||
@@ -401,36 +388,8 @@ Commands.replaceNodeByPath = (editor, path, newNode) => {
|
||||
*/
|
||||
|
||||
Commands.replaceTextByPath = (editor, path, offset, length, text, marks) => {
|
||||
const { document } = editor.value
|
||||
const node = document.assertNode(path)
|
||||
|
||||
if (length + offset > node.text.length) {
|
||||
length = node.text.length - offset
|
||||
}
|
||||
|
||||
const range = document.createRange({
|
||||
anchor: { path, offset },
|
||||
focus: { path, offset: offset + length },
|
||||
})
|
||||
|
||||
let activeMarks = document.getActiveMarksAtRange(range)
|
||||
|
||||
editor.withoutNormalizing(() => {
|
||||
editor.removeTextByPath(path, offset, length)
|
||||
|
||||
if (!marks) {
|
||||
// Do not use mark at index when marks and activeMarks are both empty
|
||||
marks = activeMarks ? activeMarks : []
|
||||
} else if (activeMarks) {
|
||||
// Do not use `has` because we may want to reset marks like font-size with
|
||||
// an updated data;
|
||||
activeMarks = activeMarks.filter(
|
||||
activeMark => !marks.find(m => activeMark.type === m.type)
|
||||
)
|
||||
|
||||
marks = activeMarks.merge(marks)
|
||||
}
|
||||
|
||||
editor.insertTextByPath(path, offset, text, marks)
|
||||
})
|
||||
}
|
||||
@@ -454,17 +413,34 @@ Commands.setMarkByPath = (
|
||||
properties,
|
||||
newProperties
|
||||
) => {
|
||||
// we call Mark.create() here because we need the complete previous mark instance
|
||||
properties = Mark.create(properties)
|
||||
newProperties = Mark.createProperties(newProperties)
|
||||
|
||||
editor.applyOperation({
|
||||
type: 'set_mark',
|
||||
path,
|
||||
offset,
|
||||
length,
|
||||
properties,
|
||||
newProperties,
|
||||
const { value } = editor
|
||||
const { document } = value
|
||||
const node = document.assertNode(path)
|
||||
|
||||
editor.withoutNormalizing(() => {
|
||||
// If it ends before the end of the node, we'll need to split to create a new
|
||||
// text with different marks.
|
||||
if (offset + length < node.text.length) {
|
||||
editor.splitNodeByPath(path, offset + length)
|
||||
}
|
||||
|
||||
// Same thing if it starts after the start. But in that case, we need to
|
||||
// update our path and offset to point to the new start.
|
||||
if (offset > 0) {
|
||||
editor.splitNodeByPath(path, offset)
|
||||
path = PathUtils.increment(path)
|
||||
offset = 0
|
||||
}
|
||||
|
||||
editor.applyOperation({
|
||||
type: 'set_mark',
|
||||
path,
|
||||
properties,
|
||||
newProperties,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -316,13 +316,16 @@ Commands.insertText = (editor, text, marks) => {
|
||||
const { value } = editor
|
||||
const { document, selection } = value
|
||||
marks = marks || selection.marks || document.getInsertMarksAtRange(selection)
|
||||
editor.insertTextAtRange(selection, text, marks)
|
||||
|
||||
// If the text was successfully inserted, and the selection had marks on it,
|
||||
// unset the selection's marks.
|
||||
if (selection.marks && document !== editor.value.document) {
|
||||
editor.select({ marks: null })
|
||||
}
|
||||
editor.withoutNormalizing(() => {
|
||||
editor.insertTextAtRange(selection, text, marks)
|
||||
|
||||
// If the text was successfully inserted, and the selection had marks on it,
|
||||
// unset the selection's marks.
|
||||
if (selection.marks && document !== editor.value.document) {
|
||||
editor.select({ marks: null })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -25,19 +25,27 @@ import Operation from '../models/operation'
|
||||
|
||||
class ElementInterface {
|
||||
/**
|
||||
* Add mark to text at `offset` and `length` in node by `path`.
|
||||
* Get the concatenated text of the node.
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
get text() {
|
||||
return this.getText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Add `mark` to text at `path`.
|
||||
*
|
||||
* @param {List|String} path
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Node}
|
||||
*/
|
||||
|
||||
addMark(path, offset, length, mark) {
|
||||
let node = this.assertDescendant(path)
|
||||
addMark(path, mark) {
|
||||
path = this.resolvePath(path)
|
||||
node = node.addMark(offset, length, mark)
|
||||
let node = this.assertDescendant(path)
|
||||
node = node.addMark(mark)
|
||||
const ret = this.replaceNode(path, node)
|
||||
return ret
|
||||
}
|
||||
@@ -268,15 +276,17 @@ class ElementInterface {
|
||||
}
|
||||
|
||||
if (PathUtils.isEqual(startPath, endPath)) {
|
||||
return startText.getActiveMarksBetweenOffsets(startOffset, endOffset)
|
||||
return startText.marks
|
||||
}
|
||||
|
||||
const startMarks = startText.getActiveMarksBetweenOffsets(
|
||||
startOffset,
|
||||
startText.text.length
|
||||
)
|
||||
if (startMarks.size === 0) return Set()
|
||||
const endMarks = endText.getActiveMarksBetweenOffsets(0, endOffset)
|
||||
const startMarks = startText.marks
|
||||
|
||||
// PERF: if start marks is empty we can return early.
|
||||
if (startMarks.size === 0) {
|
||||
return Set()
|
||||
}
|
||||
|
||||
const endMarks = endText.marks
|
||||
let marks = startMarks.intersect(endMarks)
|
||||
|
||||
// If marks is already empty, the active marks is empty
|
||||
@@ -288,12 +298,16 @@ class ElementInterface {
|
||||
|
||||
while (!PathUtils.isEqual(startPath, endPath)) {
|
||||
if (startText.text.length !== 0) {
|
||||
marks = marks.intersect(startText.getActiveMarks())
|
||||
if (marks.size === 0) return Set()
|
||||
marks = marks.intersect(startText.marks)
|
||||
|
||||
if (marks.size === 0) {
|
||||
return Set()
|
||||
}
|
||||
}
|
||||
|
||||
;[startText, startPath] = this.getNextTextAndPath(startPath)
|
||||
}
|
||||
|
||||
return marks
|
||||
}
|
||||
|
||||
@@ -804,7 +818,7 @@ class ElementInterface {
|
||||
}
|
||||
|
||||
const text = this.getDescendant(start.path)
|
||||
const marks = text.getMarksAtIndex(start.offset + 1)
|
||||
const { marks } = text
|
||||
return marks
|
||||
}
|
||||
|
||||
@@ -939,7 +953,9 @@ class ElementInterface {
|
||||
const result = []
|
||||
|
||||
this.nodes.forEach(node => {
|
||||
result.push(node.getMarksAsArray())
|
||||
result.push(
|
||||
node.object === 'text' ? node.marks.toArray() : node.getMarksAsArray()
|
||||
)
|
||||
})
|
||||
|
||||
// PERF: use only one concat rather than multiple for speed.
|
||||
@@ -958,22 +974,29 @@ class ElementInterface {
|
||||
getMarksAtPosition(path, offset) {
|
||||
path = this.resolvePath(path)
|
||||
const text = this.getDescendant(path)
|
||||
const currentMarks = text.getMarksAtIndex(offset)
|
||||
if (offset !== 0) return currentMarks
|
||||
const currentMarks = text.marks
|
||||
|
||||
if (offset !== 0) {
|
||||
return currentMarks
|
||||
}
|
||||
|
||||
const closestBlock = this.getClosestBlock(path)
|
||||
|
||||
// insert mark for empty block; the empty block are often created by split node or add marks in a range including empty blocks
|
||||
if (closestBlock.text === '') {
|
||||
// insert mark for empty block; the empty block are often created by split node or add marks in a range including empty blocks
|
||||
return currentMarks
|
||||
}
|
||||
|
||||
const previous = this.getPreviousTextAndPath(path)
|
||||
if (!previous) return Set()
|
||||
|
||||
if (!previous) {
|
||||
return Set()
|
||||
}
|
||||
|
||||
const [previousText, previousPath] = previous
|
||||
|
||||
if (closestBlock.hasDescendant(previousPath)) {
|
||||
return previousText.getMarksAtIndex(previousText.text.length)
|
||||
return previousText.marks
|
||||
}
|
||||
|
||||
return currentMarks
|
||||
@@ -1346,28 +1369,18 @@ class ElementInterface {
|
||||
getOrderedMarksBetweenPositions(startPath, startOffset, endPath, endOffset) {
|
||||
startPath = this.resolvePath(startPath)
|
||||
endPath = this.resolvePath(endPath)
|
||||
|
||||
const startText = this.getDescendant(startPath)
|
||||
|
||||
// PERF: if the paths are equal, we can just use the start.
|
||||
if (PathUtils.isEqual(startPath, endPath)) {
|
||||
return startText.getMarksBetweenOffsets(startOffset, endOffset)
|
||||
return startText.marks
|
||||
}
|
||||
|
||||
const endText = this.getDescendant(endPath)
|
||||
|
||||
const texts = this.getTextsBetweenPathPositionsAsArray(startPath, endPath)
|
||||
|
||||
return OrderedSet().withMutations(result => {
|
||||
texts.forEach(text => {
|
||||
if (text.key === startText.key) {
|
||||
result.union(
|
||||
text.getMarksBetweenOffsets(startOffset, text.text.length)
|
||||
)
|
||||
} else if (text.key === endText.key) {
|
||||
result.union(text.getMarksBetweenOffsets(0, endOffset))
|
||||
} else {
|
||||
result.union(text.getMarks())
|
||||
}
|
||||
result.union(text.marks)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1902,14 +1915,13 @@ class ElementInterface {
|
||||
* @param {List|String} path
|
||||
* @param {Number} offset
|
||||
* @param {String} text
|
||||
* @param {Set} marks
|
||||
* @return {Node}
|
||||
*/
|
||||
|
||||
insertText(path, offset, text, marks) {
|
||||
let node = this.assertDescendant(path)
|
||||
insertText(path, offset, text) {
|
||||
path = this.resolvePath(path)
|
||||
node = node.insertText(offset, text, marks)
|
||||
let node = this.assertDescendant(path)
|
||||
node = node.insertText(offset, text)
|
||||
const ret = this.replaceNode(path, node)
|
||||
return ret
|
||||
}
|
||||
@@ -2086,19 +2098,17 @@ class ElementInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove mark from text at `offset` and `length` in node.
|
||||
* Remove `mark` from text at `path`.
|
||||
*
|
||||
* @param {List} path
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Node}
|
||||
*/
|
||||
|
||||
removeMark(path, offset, length, mark) {
|
||||
let node = this.assertDescendant(path)
|
||||
removeMark(path, mark) {
|
||||
path = this.resolvePath(path)
|
||||
node = node.removeMark(offset, length, mark)
|
||||
let node = this.assertDescendant(path)
|
||||
node = node.removeMark(mark)
|
||||
const ret = this.replaceNode(path, node)
|
||||
return ret
|
||||
}
|
||||
@@ -2240,9 +2250,10 @@ class ElementInterface {
|
||||
* @return {Node}
|
||||
*/
|
||||
|
||||
setMark(path, offset, length, properties, newProperties) {
|
||||
let node = this.assertNode(path)
|
||||
node = node.updateMark(offset, length, properties, newProperties)
|
||||
setMark(path, properties, newProperties) {
|
||||
path = this.resolvePath(path)
|
||||
let node = this.assertDescendant(path)
|
||||
node = node.setMark(properties, newProperties)
|
||||
const ret = this.replaceNode(path, node)
|
||||
return ret
|
||||
}
|
||||
|
@@ -18,16 +18,6 @@ import Text from '../models/text'
|
||||
*/
|
||||
|
||||
class NodeInterface {
|
||||
/**
|
||||
* Get the concatenated text of the node.
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
get text() {
|
||||
return this.getText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first text node of a node, or the node itself.
|
||||
*
|
||||
@@ -141,8 +131,11 @@ class NodeInterface {
|
||||
*/
|
||||
|
||||
getText() {
|
||||
const children = this.object === 'text' ? this.leaves : this.nodes
|
||||
const text = children.reduce((memo, c) => memo + c.text, '')
|
||||
if (this.object === 'text') {
|
||||
return this.text
|
||||
}
|
||||
|
||||
const text = this.nodes.reduce((memo, c) => memo + c.text, '')
|
||||
return text
|
||||
}
|
||||
|
||||
|
@@ -69,7 +69,30 @@ class Node {
|
||||
|
||||
static createList(elements = []) {
|
||||
if (List.isList(elements) || Array.isArray(elements)) {
|
||||
const list = List(elements.map(Node.create))
|
||||
let array = []
|
||||
|
||||
elements.forEach(el => {
|
||||
if (
|
||||
el &&
|
||||
el.object === 'text' &&
|
||||
el.leaves &&
|
||||
Array.isArray(el.leaves)
|
||||
) {
|
||||
warning(
|
||||
false,
|
||||
'As of slate@0.46, the `leaves` property of Text nodes has been removed. Instead, each text node contains a string of text and a unique set of marks and leaves are unnecessary.'
|
||||
)
|
||||
|
||||
const texts = Text.createList(el.leaves).toArray()
|
||||
array = array.concat(texts)
|
||||
return
|
||||
}
|
||||
|
||||
const node = Node.create(el)
|
||||
array.push(node)
|
||||
})
|
||||
|
||||
const list = List(array)
|
||||
return list
|
||||
}
|
||||
|
||||
|
@@ -16,15 +16,15 @@ import invert from '../operations/invert'
|
||||
*/
|
||||
|
||||
const OPERATION_ATTRIBUTES = {
|
||||
add_mark: ['path', 'offset', 'length', 'mark', 'data'],
|
||||
add_mark: ['path', 'mark', 'data'],
|
||||
insert_node: ['path', 'node', 'data'],
|
||||
insert_text: ['path', 'offset', 'text', 'marks', 'data'],
|
||||
insert_text: ['path', 'offset', 'text', 'data'],
|
||||
merge_node: ['path', 'position', 'properties', 'target', 'data'],
|
||||
move_node: ['path', 'newPath', 'data'],
|
||||
remove_mark: ['path', 'offset', 'length', 'mark', 'data'],
|
||||
remove_mark: ['path', 'mark', 'data'],
|
||||
remove_node: ['path', 'node', 'data'],
|
||||
remove_text: ['path', 'offset', 'text', 'marks', 'data'],
|
||||
set_mark: ['path', 'offset', 'length', 'properties', 'newProperties', 'data'],
|
||||
remove_text: ['path', 'offset', 'text', 'data'],
|
||||
set_mark: ['path', 'properties', 'newProperties', 'data'],
|
||||
set_node: ['path', 'properties', 'newProperties', 'data'],
|
||||
set_selection: ['properties', 'newProperties', 'data'],
|
||||
set_value: ['properties', 'newProperties', 'data'],
|
||||
|
@@ -408,12 +408,28 @@ class Point extends Record(DEFAULTS) {
|
||||
// TODO: if we look up by path above and it differs by key, do we want to reset it to looking up by key?
|
||||
}
|
||||
|
||||
const point = this.merge({
|
||||
let point = this.merge({
|
||||
key: target.key,
|
||||
path: path == null ? node.getPath(target.key) : path,
|
||||
offset: offset == null ? 0 : Math.min(offset, target.text.length),
|
||||
})
|
||||
|
||||
// COMPAT: There is an ambiguity, since a point can exist at the end of a
|
||||
// text node, or at the start of the following one. To eliminate it we
|
||||
// enforce that if there is a following text node, we always move it there.
|
||||
if (point.offset === target.text.length) {
|
||||
const block = node.getClosestBlock(point.path)
|
||||
const next = block.getNextText()
|
||||
|
||||
if (next) {
|
||||
point = point.merge({
|
||||
key: next.key,
|
||||
path: node.getPath(next.key),
|
||||
offset: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return point
|
||||
}
|
||||
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import isPlainObject from 'is-plain-object'
|
||||
import warning from 'tiny-warning'
|
||||
import { List, OrderedSet, Record, Set } from 'immutable'
|
||||
import invariant from 'tiny-invariant'
|
||||
import { List, Record } from 'immutable'
|
||||
|
||||
import Mark from './mark'
|
||||
import Leaf from './leaf'
|
||||
import Mark from './mark'
|
||||
import KeyUtils from '../utils/key-utils'
|
||||
import memoize from '../utils/memoize'
|
||||
|
||||
/**
|
||||
* Default properties.
|
||||
@@ -14,8 +13,9 @@ import memoize from '../utils/memoize'
|
||||
*/
|
||||
|
||||
const DEFAULTS = {
|
||||
leaves: undefined,
|
||||
key: undefined,
|
||||
marks: undefined,
|
||||
text: undefined,
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,15 +38,10 @@ class Text extends Record(DEFAULTS) {
|
||||
}
|
||||
|
||||
if (typeof attrs === 'string') {
|
||||
attrs = { leaves: [{ text: attrs }] }
|
||||
attrs = { text: attrs }
|
||||
}
|
||||
|
||||
if (isPlainObject(attrs)) {
|
||||
if (attrs.text) {
|
||||
const { text, marks, key } = attrs
|
||||
attrs = { key, leaves: [{ text, marks }] }
|
||||
}
|
||||
|
||||
return Text.fromJSON(attrs)
|
||||
}
|
||||
|
||||
@@ -85,37 +80,16 @@ class Text extends Record(DEFAULTS) {
|
||||
return object
|
||||
}
|
||||
|
||||
const { key = KeyUtils.create() } = object
|
||||
let { leaves } = object
|
||||
|
||||
if (!leaves) {
|
||||
if (object.ranges) {
|
||||
warning(
|
||||
false,
|
||||
'As of slate@0.27.0, the `ranges` property of Slate objects has been renamed to `leaves`.'
|
||||
)
|
||||
|
||||
leaves = object.ranges
|
||||
} else {
|
||||
leaves = List()
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(leaves)) {
|
||||
leaves = List(leaves.map(x => Leaf.create(x)))
|
||||
} else if (List.isList(leaves)) {
|
||||
leaves = leaves.map(x => Leaf.create(x))
|
||||
} else {
|
||||
throw new Error('leaves must be either Array or Immutable.List')
|
||||
}
|
||||
|
||||
if (leaves.size === 0) {
|
||||
leaves = leaves.push(Leaf.create())
|
||||
}
|
||||
invariant(
|
||||
object.leaves == null,
|
||||
'As of slate@0.46, the `leaves` property of text nodes has been removed! Each individual leaf should be created as a text node instead.'
|
||||
)
|
||||
|
||||
const { text = '', marks = [], key = KeyUtils.create() } = object
|
||||
const node = new Text({
|
||||
leaves: Leaf.createLeaves(leaves),
|
||||
key,
|
||||
text,
|
||||
marks: Mark.createSet(marks),
|
||||
})
|
||||
|
||||
return node
|
||||
@@ -133,122 +107,58 @@ class Text extends Record(DEFAULTS) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the 'first' leaf at offset; By 'first' the alorighthm prefers `endOffset === offset` than `startOffset === offset`
|
||||
* Corner Cases:
|
||||
* 1. if offset is negative, return the first leaf;
|
||||
* 2. if offset is larger than text length, the leaf is null, startOffset, endOffset and index is of the last leaf
|
||||
* Add a `mark`.
|
||||
*
|
||||
* @param {number}
|
||||
* @returns {Object}
|
||||
* @property {number} startOffset
|
||||
* @property {number} endOffset
|
||||
* @property {number} index
|
||||
* @property {Leaf} leaf
|
||||
*/
|
||||
|
||||
searchLeafAtOffset(offset) {
|
||||
let endOffset = 0
|
||||
let startOffset = 0
|
||||
let index = -1
|
||||
|
||||
const leaf = this.leaves.find(l => {
|
||||
index++
|
||||
startOffset = endOffset
|
||||
endOffset = startOffset + l.text.length
|
||||
return endOffset >= offset
|
||||
})
|
||||
|
||||
return {
|
||||
leaf,
|
||||
endOffset,
|
||||
index,
|
||||
startOffset,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a `mark` at `index` and `length`.
|
||||
*
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Text}
|
||||
*/
|
||||
|
||||
addMark(index, length, mark) {
|
||||
const marks = Set.of(mark)
|
||||
return this.addMarks(index, length, marks)
|
||||
addMark(mark) {
|
||||
mark = Mark.create(mark)
|
||||
const { marks } = this
|
||||
const next = marks.add(mark)
|
||||
const node = this.set('marks', next)
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a `set` of marks at `index` and `length`.
|
||||
* Corner Cases:
|
||||
* 1. If empty text, and if length === 0 and index === 0, will make sure the text contain an empty leaf with the given mark.
|
||||
* Add a set of `marks`.
|
||||
*
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Set<Mark>} set
|
||||
* @param {Set<Mark>} marks
|
||||
* @return {Text}
|
||||
*/
|
||||
|
||||
addMarks(index, length, set) {
|
||||
if (this.text === '' && length === 0 && index === 0) {
|
||||
const { leaves } = this
|
||||
const first = leaves.first()
|
||||
|
||||
if (!first) {
|
||||
return this.set(
|
||||
'leaves',
|
||||
List.of(Leaf.fromJSON({ text: '', marks: set }))
|
||||
)
|
||||
}
|
||||
|
||||
const newFirst = first.addMarks(set)
|
||||
if (newFirst === first) return this
|
||||
return this.set('leaves', List.of(newFirst))
|
||||
}
|
||||
|
||||
if (this.text === '') return this
|
||||
if (length === 0) return this
|
||||
if (index >= this.text.length) return this
|
||||
|
||||
const [before, bundle] = Leaf.splitLeaves(this.leaves, index)
|
||||
const [middle, after] = Leaf.splitLeaves(bundle, length)
|
||||
const leaves = before.concat(middle.map(x => x.addMarks(set)), after)
|
||||
return this.setLeaves(leaves)
|
||||
addMarks(marks) {
|
||||
marks = Mark.createSet(marks)
|
||||
const node = this.set('marks', this.marks.union(marks))
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the leaves for a list of `decorations`.
|
||||
* Get the leaves for the text node, with `decorations`.
|
||||
*
|
||||
* @param {List} decorations (optional)
|
||||
* @param {List<Decoration>} decorations
|
||||
* @return {List<Leaf>}
|
||||
*/
|
||||
|
||||
getLeaves(decorations) {
|
||||
let { leaves } = this
|
||||
const { key, text, marks } = this
|
||||
const leaf = Leaf.create({ text, marks })
|
||||
let leaves = Leaf.createList([leaf])
|
||||
|
||||
// PERF: We can exit early without decorations.
|
||||
if (!decorations || decorations.size === 0) return leaves
|
||||
|
||||
// HACK: We shouldn't need this, because text nodes should never be in a
|
||||
// position of not having any leaves...
|
||||
if (leaves.size === 0) {
|
||||
const marks = decorations.map(d => d.mark)
|
||||
const leaf = Leaf.create({ marks })
|
||||
return List([leaf])
|
||||
if (!decorations || decorations.size === 0) {
|
||||
return leaves
|
||||
}
|
||||
|
||||
// HACK: this shouldn't be necessary, because the loop below should handle
|
||||
// the `0` case without failures. It may already even, not sure.
|
||||
if (this.text.length === 0) {
|
||||
const marks = decorations.map(d => d.mark)
|
||||
const leaf = Leaf.create({ marks })
|
||||
return List([leaf])
|
||||
if (text === '') {
|
||||
const decMarks = decorations.map(d => d.mark)
|
||||
const l = Leaf.create({ marks: decMarks })
|
||||
return List([l])
|
||||
}
|
||||
|
||||
const { key, text } = this
|
||||
|
||||
decorations.forEach(dec => {
|
||||
const { start, end, mark } = dec
|
||||
const hasStart = start.key === key
|
||||
@@ -276,274 +186,49 @@ class Text extends Record(DEFAULTS) {
|
||||
return Leaf.createLeaves(leaves)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the active marks on between two offsets
|
||||
* Corner Cases:
|
||||
* 1. if startOffset is equal or bigger than endOffset, then return Set();
|
||||
* 2. If no text is selected between start and end, then return Set()
|
||||
*
|
||||
* @return {Set<Mark>}
|
||||
*/
|
||||
|
||||
getActiveMarksBetweenOffsets(startOffset, endOffset) {
|
||||
if (startOffset <= 0 && endOffset >= this.text.length) {
|
||||
return this.getActiveMarks()
|
||||
}
|
||||
|
||||
if (startOffset >= endOffset) return Set()
|
||||
// For empty text in a paragraph, use getActiveMarks;
|
||||
if (this.text === '') return this.getActiveMarks()
|
||||
|
||||
let result = null
|
||||
let leafEnd = 0
|
||||
|
||||
this.leaves.forEach(leaf => {
|
||||
const leafStart = leafEnd
|
||||
leafEnd = leafStart + leaf.text.length
|
||||
|
||||
if (leafEnd <= startOffset) return
|
||||
if (leafStart >= endOffset) return false
|
||||
|
||||
if (!result) {
|
||||
result = leaf.marks
|
||||
return
|
||||
}
|
||||
|
||||
result = result.intersect(leaf.marks)
|
||||
if (result && result.size === 0) return false
|
||||
return false
|
||||
})
|
||||
|
||||
return result || Set()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the active marks on the text
|
||||
*
|
||||
* @return {Set<Mark>}
|
||||
*/
|
||||
|
||||
getActiveMarks() {
|
||||
if (this.leaves.size === 0) return Set()
|
||||
|
||||
const result = this.leaves.first().marks
|
||||
if (result.size === 0) return result
|
||||
|
||||
return result.toOrderedSet().withMutations(x => {
|
||||
this.leaves.forEach(c => {
|
||||
x.intersect(c.marks)
|
||||
if (x.size === 0) return false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the marks on between two offsets
|
||||
* Corner Cases:
|
||||
* 1. if startOffset is equal or bigger than endOffset, then return Set();
|
||||
* 2. If no text is selected between start and end, then return Set()
|
||||
*
|
||||
* @return {OrderedSet<Mark>}
|
||||
*/
|
||||
|
||||
getMarksBetweenOffsets(startOffset, endOffset) {
|
||||
if (startOffset <= 0 && endOffset >= this.text.length) {
|
||||
return this.getMarks()
|
||||
}
|
||||
|
||||
if (startOffset >= endOffset) return Set()
|
||||
// For empty text in a paragraph, use getActiveMarks;
|
||||
if (this.text === '') return this.getActiveMarks()
|
||||
|
||||
let result = null
|
||||
let leafEnd = 0
|
||||
|
||||
this.leaves.forEach(leaf => {
|
||||
const leafStart = leafEnd
|
||||
leafEnd = leafStart + leaf.text.length
|
||||
|
||||
if (leafEnd <= startOffset) return
|
||||
if (leafStart >= endOffset) return false
|
||||
|
||||
if (!result) {
|
||||
result = leaf.marks
|
||||
return
|
||||
}
|
||||
|
||||
result = result.union(leaf.marks)
|
||||
})
|
||||
|
||||
return result || Set()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the marks on the text.
|
||||
*
|
||||
* @return {OrderedSet<Mark>}
|
||||
*/
|
||||
|
||||
getMarks() {
|
||||
const array = this.getMarksAsArray()
|
||||
return new OrderedSet(array)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the marks on the text as an array
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
|
||||
getMarksAsArray() {
|
||||
if (this.leaves.size === 0) return []
|
||||
const first = this.leaves.first().marks
|
||||
if (this.leaves.size === 1) return first.toArray()
|
||||
|
||||
const result = []
|
||||
|
||||
this.leaves.forEach(leaf => {
|
||||
result.push(leaf.marks.toArray())
|
||||
})
|
||||
|
||||
return Array.prototype.concat.apply(first.toArray(), result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the marks on the text at `index`.
|
||||
* Corner Cases:
|
||||
* 1. if no text is before the index, and index !== 0, then return Set()
|
||||
* 2. (for insert after split node or mark at range) if index === 0, and text === '', then return the leaf.marks
|
||||
* 3. if index === 0, text !== '', return Set()
|
||||
*
|
||||
*
|
||||
* @param {Number} index
|
||||
* @return {Set<Mark>}
|
||||
*/
|
||||
|
||||
getMarksAtIndex(index) {
|
||||
const { leaf } = this.searchLeafAtOffset(index)
|
||||
if (!leaf) return Set()
|
||||
return leaf.marks
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert `text` at `index`.
|
||||
*
|
||||
* @param {Numbder} offset
|
||||
* @param {String} text
|
||||
* @param {Set} marks (optional)
|
||||
* @param {Number} index
|
||||
* @param {String} string
|
||||
* @return {Text}
|
||||
*/
|
||||
|
||||
insertText(offset, text, marks) {
|
||||
if (this.text === '') {
|
||||
return this.set('leaves', List.of(Leaf.create({ text, marks })))
|
||||
}
|
||||
|
||||
if (text.length === 0) return this
|
||||
if (!marks) marks = Set()
|
||||
|
||||
const { startOffset, leaf, index } = this.searchLeafAtOffset(offset)
|
||||
const delta = offset - startOffset
|
||||
const beforeText = leaf.text.slice(0, delta)
|
||||
const afterText = leaf.text.slice(delta)
|
||||
const { leaves } = this
|
||||
|
||||
if (leaf.marks.equals(marks)) {
|
||||
return this.set(
|
||||
'leaves',
|
||||
leaves.set(index, leaf.set('text', beforeText + text + afterText))
|
||||
)
|
||||
}
|
||||
|
||||
const nextLeaves = leaves.splice(
|
||||
index,
|
||||
1,
|
||||
leaf.set('text', beforeText),
|
||||
Leaf.create({ text, marks }),
|
||||
leaf.set('text', afterText)
|
||||
)
|
||||
|
||||
return this.setLeaves(nextLeaves)
|
||||
insertText(index, string) {
|
||||
const { text } = this
|
||||
const next = text.slice(0, index) + string + text.slice(index)
|
||||
const node = this.set('text', next)
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a `mark` at `index` and `length`.
|
||||
* Remove a `mark`.
|
||||
*
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Text}
|
||||
*/
|
||||
|
||||
removeMark(index, length, mark) {
|
||||
if (this.text === '' && index === 0 && length === 0) {
|
||||
const first = this.leaves.first()
|
||||
if (!first) return this
|
||||
const newFirst = first.removeMark(mark)
|
||||
if (newFirst === first) return this
|
||||
return this.set('leaves', List.of(newFirst))
|
||||
}
|
||||
|
||||
if (length <= 0) return this
|
||||
if (index >= this.text.length) return this
|
||||
const [before, bundle] = Leaf.splitLeaves(this.leaves, index)
|
||||
const [middle, after] = Leaf.splitLeaves(bundle, length)
|
||||
const leaves = before.concat(middle.map(x => x.removeMark(mark)), after)
|
||||
return this.setLeaves(leaves)
|
||||
removeMark(mark) {
|
||||
mark = Mark.create(mark)
|
||||
const { marks } = this
|
||||
const next = marks.remove(mark)
|
||||
const node = this.set('marks', next)
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove text from the text node at `start` for `length`.
|
||||
* Remove text from the text node at `index` for `length`.
|
||||
*
|
||||
* @param {Number} start
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @return {Text}
|
||||
*/
|
||||
|
||||
removeText(start, length) {
|
||||
if (length <= 0) return this
|
||||
if (start >= this.text.length) return this
|
||||
|
||||
// PERF: For simple backspace, we can operate directly on the leaf
|
||||
if (length === 1) {
|
||||
const { leaf, index, startOffset } = this.searchLeafAtOffset(start + 1)
|
||||
const offset = start - startOffset
|
||||
|
||||
if (leaf) {
|
||||
if (leaf.text.length === 1) {
|
||||
const leaves = this.leaves.remove(index)
|
||||
return this.setLeaves(leaves)
|
||||
}
|
||||
|
||||
const beforeText = leaf.text.slice(0, offset)
|
||||
const afterText = leaf.text.slice(offset + length)
|
||||
const text = beforeText + afterText
|
||||
|
||||
if (text.length > 0) {
|
||||
return this.set(
|
||||
'leaves',
|
||||
this.leaves.set(index, leaf.set('text', text))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const [before, bundle] = Leaf.splitLeaves(this.leaves, start)
|
||||
const after = Leaf.splitLeaves(bundle, length)[1]
|
||||
const leaves = Leaf.createLeaves(before.concat(after))
|
||||
|
||||
if (leaves.size === 1) {
|
||||
const first = leaves.first()
|
||||
|
||||
if (first.text === '') {
|
||||
return this.set(
|
||||
'leaves',
|
||||
List.of(first.set('marks', this.getActiveMarks()))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return this.set('leaves', leaves)
|
||||
removeText(index, length) {
|
||||
const { text } = this
|
||||
const next = text.slice(0, index) + text.slice(index + length)
|
||||
const node = this.set('text', next)
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,9 +241,8 @@ class Text extends Record(DEFAULTS) {
|
||||
toJSON(options = {}) {
|
||||
const object = {
|
||||
object: this.object,
|
||||
leaves: this.getLeaves()
|
||||
.toArray()
|
||||
.map(r => r.toJSON()),
|
||||
text: this.text,
|
||||
marks: this.marks.toArray().map(m => m.toJSON()),
|
||||
}
|
||||
|
||||
if (options.preserveKeys) {
|
||||
@@ -569,100 +253,50 @@ class Text extends Record(DEFAULTS) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a `mark` at `index` and `length` with `properties`.
|
||||
* Set a `newProperties` on an existing `mark`.
|
||||
*
|
||||
* @param {Number} index
|
||||
* @param {Number} length
|
||||
* @param {Object} properties
|
||||
* @param {Object} mark
|
||||
* @param {Object} newProperties
|
||||
* @return {Text}
|
||||
*/
|
||||
|
||||
updateMark(index, length, properties, newProperties) {
|
||||
setMark(properties, newProperties) {
|
||||
const { marks } = this
|
||||
const mark = Mark.create(properties)
|
||||
const newMark = mark.merge(newProperties)
|
||||
|
||||
if (this.text === '' && length === 0 && index === 0) {
|
||||
const { leaves } = this
|
||||
const first = leaves.first()
|
||||
if (!first) return this
|
||||
const newFirst = first.updateMark(mark, newMark)
|
||||
if (newFirst === first) return this
|
||||
return this.set('leaves', List.of(newFirst))
|
||||
}
|
||||
|
||||
if (length <= 0) return this
|
||||
if (index >= this.text.length) return this
|
||||
|
||||
const [before, bundle] = Leaf.splitLeaves(this.leaves, index)
|
||||
const [middle, after] = Leaf.splitLeaves(bundle, length)
|
||||
|
||||
const leaves = before.concat(
|
||||
middle.map(x => x.updateMark(mark, newMark)),
|
||||
after
|
||||
)
|
||||
|
||||
return this.setLeaves(leaves)
|
||||
const next = marks.remove(mark).add(newMark)
|
||||
const node = this.set('marks', next)
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* Split this text and return two different texts
|
||||
* @param {Number} position
|
||||
* Split the node into two at `index`.
|
||||
*
|
||||
* @param {Number} index
|
||||
* @returns {Array<Text>}
|
||||
*/
|
||||
|
||||
splitText(offset) {
|
||||
const splitted = Leaf.splitLeaves(this.leaves, offset)
|
||||
const one = this.set('leaves', splitted[0])
|
||||
const two = this.set('leaves', splitted[1]).regenerateKey()
|
||||
splitText(index) {
|
||||
const { text } = this
|
||||
const one = this.set('text', text.slice(0, index))
|
||||
const two = this.set('text', text.slice(index)).regenerateKey()
|
||||
return [one, two]
|
||||
}
|
||||
|
||||
/**
|
||||
* merge this text and another text at the end
|
||||
* @param {Text} text
|
||||
* @returns {Text}
|
||||
*/
|
||||
|
||||
mergeText(text) {
|
||||
const leaves = this.leaves.concat(text.leaves)
|
||||
return this.setLeaves(leaves)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set leaves with normalized `leaves`
|
||||
* Merge the node with an `other` text node.
|
||||
*
|
||||
* @param {List} leaves
|
||||
* @param {Text} other
|
||||
* @returns {Text}
|
||||
*/
|
||||
|
||||
setLeaves(leaves) {
|
||||
leaves = Leaf.createLeaves(leaves)
|
||||
|
||||
if (leaves.size === 1) {
|
||||
const first = leaves.first()
|
||||
|
||||
if (!first.marks || first.marks.size === 0) {
|
||||
if (first.text === '') {
|
||||
return this.set('leaves', List([Leaf.create()]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (leaves.size === 0) {
|
||||
leaves = leaves.push(Leaf.create())
|
||||
}
|
||||
|
||||
return this.set('leaves', leaves)
|
||||
mergeText(other) {
|
||||
const next = this.text + other.text
|
||||
const node = this.set('text', next)
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Memoize read methods.
|
||||
*/
|
||||
|
||||
memoize(Text.prototype, ['getActiveMarks', 'getMarks', 'getMarksAsArray'])
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*
|
||||
|
@@ -2,6 +2,7 @@ import isPlainObject from 'is-plain-object'
|
||||
import invariant from 'tiny-invariant'
|
||||
import { Record, Set, List } from 'immutable'
|
||||
|
||||
import Mark from './mark'
|
||||
import PathUtils from '../utils/path-utils'
|
||||
import Data from './data'
|
||||
import Decoration from './decoration'
|
||||
@@ -418,20 +419,19 @@ class Value extends Record(DEFAULTS) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add mark to text at `offset` and `length` in node by `path`.
|
||||
* Add `mark` to text at `path`.
|
||||
*
|
||||
* @param {List|String} path
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Value}
|
||||
*/
|
||||
|
||||
addMark(path, offset, length, mark) {
|
||||
addMark(path, mark) {
|
||||
mark = Mark.create(mark)
|
||||
let value = this
|
||||
let { document } = value
|
||||
document = document.addMark(path, offset, length, mark)
|
||||
value = this.set('document', document)
|
||||
document = document.addMark(path, mark)
|
||||
value = value.set('document', document)
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -462,23 +462,23 @@ class Value extends Record(DEFAULTS) {
|
||||
* @param {List|String} path
|
||||
* @param {Number} offset
|
||||
* @param {String} text
|
||||
* @param {Set} marks
|
||||
* @return {Value}
|
||||
*/
|
||||
|
||||
insertText(path, offset, text, marks) {
|
||||
insertText(path, offset, text) {
|
||||
let value = this
|
||||
let { document } = value
|
||||
const node = document.assertNode(path)
|
||||
document = document.insertText(path, offset, text, marks)
|
||||
let node = document.assertNode(path)
|
||||
document = document.insertText(path, offset, text)
|
||||
node = document.assertNode(path)
|
||||
value = value.set('document', document)
|
||||
|
||||
value = value.mapRanges(range => {
|
||||
return range.updatePoints(point => {
|
||||
return point.key === node.key && point.offset >= offset
|
||||
? point.setOffset(point.offset + text.length)
|
||||
: point
|
||||
})
|
||||
value = value.mapPoints(point => {
|
||||
if (point.key === node.key && point.offset >= offset) {
|
||||
return point.setOffset(point.offset + text.length)
|
||||
} else {
|
||||
return point
|
||||
}
|
||||
})
|
||||
|
||||
return value
|
||||
@@ -537,31 +537,31 @@ class Value extends Record(DEFAULTS) {
|
||||
moveNode(path, newPath, newIndex = 0) {
|
||||
let value = this
|
||||
let { document } = value
|
||||
|
||||
if (PathUtils.isEqual(path, newPath)) {
|
||||
return value
|
||||
}
|
||||
|
||||
document = document.moveNode(path, newPath, newIndex)
|
||||
value = value.set('document', document)
|
||||
|
||||
value = value.mapRanges(range =>
|
||||
range.updatePoints(point => point.setPath(null))
|
||||
)
|
||||
|
||||
value = value.mapPoints(point => point.setPath(null))
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove mark from text at `offset` and `length` in node.
|
||||
* Remove `mark` at `path`.
|
||||
*
|
||||
* @param {List|String} path
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @return {Value}
|
||||
*/
|
||||
|
||||
removeMark(path, offset, length, mark) {
|
||||
removeMark(path, mark) {
|
||||
mark = Mark.create(mark)
|
||||
let value = this
|
||||
let { document } = value
|
||||
document = document.removeMark(path, offset, length, mark)
|
||||
value = this.set('document', document)
|
||||
document = document.removeMark(path, mark)
|
||||
value = value.set('document', document)
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -627,22 +627,20 @@ class Value extends Record(DEFAULTS) {
|
||||
const start = offset
|
||||
const end = offset + length
|
||||
|
||||
value = value.mapRanges(range => {
|
||||
return range.updatePoints(point => {
|
||||
if (point.key !== node.key) {
|
||||
return point
|
||||
}
|
||||
|
||||
if (point.offset >= end) {
|
||||
return point.setOffset(point.offset - length)
|
||||
}
|
||||
|
||||
if (point.offset > start) {
|
||||
return point.setOffset(start)
|
||||
}
|
||||
|
||||
value = value.mapPoints(point => {
|
||||
if (point.key !== node.key) {
|
||||
return point
|
||||
})
|
||||
}
|
||||
|
||||
if (point.offset >= end) {
|
||||
return point.setOffset(point.offset - length)
|
||||
}
|
||||
|
||||
if (point.offset > start) {
|
||||
return point.setOffset(start)
|
||||
}
|
||||
|
||||
return point
|
||||
})
|
||||
|
||||
return value
|
||||
@@ -668,17 +666,15 @@ class Value extends Record(DEFAULTS) {
|
||||
* Set `properties` on `mark` on text at `offset` and `length` in node.
|
||||
*
|
||||
* @param {List|String} path
|
||||
* @param {Number} offset
|
||||
* @param {Number} length
|
||||
* @param {Mark} mark
|
||||
* @param {Object} properties
|
||||
* @return {Value}
|
||||
*/
|
||||
|
||||
setMark(path, offset, length, mark, properties) {
|
||||
setMark(path, mark, properties) {
|
||||
let value = this
|
||||
let { document } = value
|
||||
document = document.setMark(path, offset, length, mark, properties)
|
||||
document = document.setMark(path, mark, properties)
|
||||
value = value.set('document', document)
|
||||
return value
|
||||
}
|
||||
@@ -793,6 +789,10 @@ class Value extends Record(DEFAULTS) {
|
||||
return value
|
||||
}
|
||||
|
||||
mapPoints(iterator) {
|
||||
return this.mapRanges(range => range.updatePoints(iterator))
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON representation of the value.
|
||||
*
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import Debug from 'debug'
|
||||
|
||||
import Operation from '../models/operation'
|
||||
import PathUtils from '../utils/path-utils'
|
||||
|
||||
/**
|
||||
* Debug.
|
||||
@@ -26,8 +25,8 @@ function applyOperation(value, op) {
|
||||
|
||||
switch (type) {
|
||||
case 'add_mark': {
|
||||
const { path, offset, length, mark } = op
|
||||
const next = value.addMark(path, offset, length, mark)
|
||||
const { path, mark } = op
|
||||
const next = value.addMark(path, mark)
|
||||
return next
|
||||
}
|
||||
|
||||
@@ -51,18 +50,13 @@ function applyOperation(value, op) {
|
||||
|
||||
case 'move_node': {
|
||||
const { path, newPath } = op
|
||||
|
||||
if (PathUtils.isEqual(path, newPath)) {
|
||||
return value
|
||||
}
|
||||
|
||||
const next = value.moveNode(path, newPath)
|
||||
return next
|
||||
}
|
||||
|
||||
case 'remove_mark': {
|
||||
const { path, offset, length, mark } = op
|
||||
const next = value.removeMark(path, offset, length, mark)
|
||||
const { path, mark } = op
|
||||
const next = value.removeMark(path, mark)
|
||||
return next
|
||||
}
|
||||
|
||||
@@ -79,14 +73,8 @@ function applyOperation(value, op) {
|
||||
}
|
||||
|
||||
case 'set_mark': {
|
||||
const { path, offset, length, properties, newProperties } = op
|
||||
const next = value.setMark(
|
||||
path,
|
||||
offset,
|
||||
length,
|
||||
properties,
|
||||
newProperties
|
||||
)
|
||||
const { path, properties, newProperties } = op
|
||||
const next = value.setMark(path, properties, newProperties)
|
||||
return next
|
||||
}
|
||||
|
||||
|
@@ -154,18 +154,40 @@ function CorePlugin(options = {}) {
|
||||
},
|
||||
},
|
||||
|
||||
// Merge adjacent text nodes.
|
||||
// Merge adjacent text nodes with the same marks.
|
||||
{
|
||||
match: { object: 'text' },
|
||||
next: [{ object: 'block' }, { object: 'inline' }],
|
||||
next: (next, match) => {
|
||||
return next.object !== 'text' || !match.marks.equals(next.marks)
|
||||
},
|
||||
normalize: (editor, error) => {
|
||||
const { code, next } = error
|
||||
|
||||
if (code === 'next_sibling_object_invalid') {
|
||||
if (code === 'next_sibling_invalid') {
|
||||
editor.mergeNodeByKey(next.key)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// Remove extra adjacent empty text nodes.
|
||||
{
|
||||
match: { object: 'text' },
|
||||
previous: prev => {
|
||||
return prev.object !== 'text' || prev.text !== ''
|
||||
},
|
||||
next: next => {
|
||||
return next.object !== 'text' || next.text !== ''
|
||||
},
|
||||
normalize: (editor, error) => {
|
||||
const { code, next, previous } = error
|
||||
|
||||
if (code === 'next_sibling_invalid') {
|
||||
editor.removeNodeByKey(next.key)
|
||||
} else if (code === 'previous_sibling_invalid') {
|
||||
editor.removeNodeByKey(previous.key)
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
@@ -243,7 +243,12 @@ function testRules(object, rules) {
|
||||
*/
|
||||
|
||||
function validateRules(object, rule, rules, options = {}) {
|
||||
const { every = false } = options
|
||||
const { every = false, match = null } = options
|
||||
|
||||
if (typeof rule === 'function') {
|
||||
const valid = rule(object, match)
|
||||
return valid ? null : fail('node_invalid', { rule, node: object })
|
||||
}
|
||||
|
||||
if (Array.isArray(rule)) {
|
||||
const array = rule.length ? rule : [{}]
|
||||
@@ -306,7 +311,9 @@ function validateData(node, rule) {
|
||||
|
||||
function validateMarks(node, rule) {
|
||||
if (rule.marks == null) return
|
||||
const marks = node.getMarks().toArray()
|
||||
|
||||
const marks =
|
||||
node.object === 'text' ? node.marks.toArray() : node.getMarks().toArray()
|
||||
|
||||
for (const mark of marks) {
|
||||
const valid = rule.marks.some(
|
||||
@@ -569,7 +576,7 @@ function validateNext(node, child, next, index, rules) {
|
||||
if (rule.next == null) continue
|
||||
if (!testRules(child, rule.match)) continue
|
||||
|
||||
const error = validateRules(next, rule.next)
|
||||
const error = validateRules(next, rule.next, [], { match: child })
|
||||
if (!error) continue
|
||||
|
||||
error.rule = rule
|
||||
|
@@ -23,8 +23,10 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<anchor />
|
||||
<b>rd</b>
|
||||
wo
|
||||
<b>
|
||||
<anchor />rd
|
||||
</b>
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<b>an</b>
|
||||
|
@@ -10,14 +10,18 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>
|
||||
wo<anchor />rd
|
||||
</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>
|
||||
an<focus />other
|
||||
</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
@@ -27,9 +31,12 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>
|
||||
wo<anchor />
|
||||
<b>rd</b>
|
||||
wo
|
||||
<b>
|
||||
<anchor />rd
|
||||
</b>
|
||||
</link>
|
||||
<b />
|
||||
</paragraph>
|
||||
@@ -39,6 +46,7 @@ export const output = (
|
||||
<b>an</b>
|
||||
<focus />other
|
||||
</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -3,15 +3,14 @@
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
editor.replaceMark('italic', 'bold').insertText('a')
|
||||
editor.addMark('bold').insertText('a')
|
||||
}
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<i />
|
||||
<cursor />word
|
||||
word<cursor />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
@@ -21,8 +20,9 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<b>a</b>
|
||||
<cursor />word
|
||||
word<b>
|
||||
a<cursor />
|
||||
</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
@@ -0,0 +1,28 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
editor.addMark('bold').insertText('a')
|
||||
}
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<cursor />rd
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<b>a</b>
|
||||
<cursor />rd
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
@@ -0,0 +1,44 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
editor.addMark('bold')
|
||||
}
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<i>
|
||||
<anchor />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<i>an</i>
|
||||
<focus />other
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo
|
||||
<b>
|
||||
<i>
|
||||
<anchor />rd
|
||||
</i>
|
||||
</b>
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<b>
|
||||
<i>an</i>
|
||||
</b>
|
||||
<focus />other
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
@@ -0,0 +1,47 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
editor.addMark('bold')
|
||||
}
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<i>
|
||||
wo<anchor />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<i>
|
||||
an<focus />other
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<i>wo</i>
|
||||
<b>
|
||||
<i>
|
||||
<anchor />rd
|
||||
</i>
|
||||
</b>
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<b>
|
||||
<i>an</i>
|
||||
</b>
|
||||
<i>
|
||||
<focus />other
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
@@ -10,9 +10,8 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<i>
|
||||
wo<focus />rd
|
||||
<anchor />wo<focus />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
@@ -23,12 +22,14 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<b>
|
||||
<i>wo</i>
|
||||
<i>
|
||||
<anchor />wo
|
||||
</i>
|
||||
</b>
|
||||
<focus />
|
||||
<i>rd</i>
|
||||
<i>
|
||||
<focus />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -20,8 +20,9 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<b>w</b>
|
||||
<b>
|
||||
<anchor />w
|
||||
</b>
|
||||
<focus />ord
|
||||
</paragraph>
|
||||
</document>
|
||||
|
@@ -20,9 +20,10 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wor<anchor />
|
||||
<b>d</b>
|
||||
<focus />
|
||||
wor
|
||||
<b>
|
||||
<anchor />d<focus />
|
||||
</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -20,8 +20,10 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
w<anchor />
|
||||
<b>o</b>
|
||||
w
|
||||
<b>
|
||||
<anchor />o
|
||||
</b>
|
||||
<focus />rd
|
||||
</paragraph>
|
||||
</document>
|
||||
|
@@ -20,9 +20,9 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<b>word</b>
|
||||
<focus />
|
||||
<b>
|
||||
<anchor />word<focus />
|
||||
</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -27,8 +27,9 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<b thing="value">w</b>
|
||||
<b thing="value">
|
||||
<anchor />w
|
||||
</b>
|
||||
<focus />ord
|
||||
</paragraph>
|
||||
</document>
|
||||
|
@@ -23,8 +23,9 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<b thing="value">w</b>
|
||||
<b thing="value">
|
||||
<anchor />w
|
||||
</b>
|
||||
<focus />ord
|
||||
</paragraph>
|
||||
</document>
|
||||
|
@@ -23,9 +23,11 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<anchor />
|
||||
wo
|
||||
<i>
|
||||
<b>rd</b>
|
||||
<b>
|
||||
<anchor />rd
|
||||
</b>
|
||||
</i>
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
|
@@ -10,14 +10,18 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>
|
||||
wo<anchor />rd
|
||||
</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>
|
||||
an<focus />other
|
||||
</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
@@ -27,10 +31,13 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>
|
||||
wo<anchor />
|
||||
wo
|
||||
<i>
|
||||
<b>rd</b>
|
||||
<b>
|
||||
<anchor />rd
|
||||
</b>
|
||||
</i>
|
||||
</link>
|
||||
<i>
|
||||
@@ -47,6 +54,7 @@ export const output = (
|
||||
</i>
|
||||
<focus />other
|
||||
</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -38,8 +38,9 @@ export const output = (
|
||||
<u>
|
||||
<i>ita</i>
|
||||
</u>
|
||||
<focus />
|
||||
<i>lic</i>
|
||||
<i>
|
||||
<focus />lic
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -0,0 +1,32 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
editor.addMarks(['bold', 'italic']).insertText('a')
|
||||
}
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
word<cursor />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
word
|
||||
<i>
|
||||
<b>
|
||||
a<cursor />
|
||||
</b>
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
@@ -0,0 +1,30 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
editor.addMarks(['bold', 'italic']).insertText('a')
|
||||
}
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<cursor />rd
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<i>
|
||||
<b>a</b>
|
||||
</i>
|
||||
<cursor />rd
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
@@ -20,9 +20,10 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<i>
|
||||
<b>w</b>
|
||||
<b>
|
||||
<anchor />w
|
||||
</b>
|
||||
</i>
|
||||
<focus />ord
|
||||
</paragraph>
|
||||
|
@@ -10,9 +10,8 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<i>
|
||||
wo<focus />rd
|
||||
<anchor />wo<focus />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
@@ -23,14 +22,16 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<u>
|
||||
<b>
|
||||
<i>wo</i>
|
||||
<i>
|
||||
<anchor />wo
|
||||
</i>
|
||||
</b>
|
||||
</u>
|
||||
<focus />
|
||||
<i>rd</i>
|
||||
<i>
|
||||
<focus />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -20,11 +20,12 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wor<anchor />
|
||||
wor
|
||||
<i>
|
||||
<b>d</b>
|
||||
<b>
|
||||
<anchor />d<focus />
|
||||
</b>
|
||||
</i>
|
||||
<focus />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -20,9 +20,11 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
w<anchor />
|
||||
w
|
||||
<i>
|
||||
<b>o</b>
|
||||
<b>
|
||||
<anchor />o
|
||||
</b>
|
||||
</i>
|
||||
<focus />rd
|
||||
</paragraph>
|
||||
|
@@ -20,11 +20,11 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<i>
|
||||
<b>word</b>
|
||||
<b>
|
||||
<anchor />word<focus />
|
||||
</b>
|
||||
</i>
|
||||
<focus />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -5,23 +5,16 @@ import h from '../../../helpers/h'
|
||||
import { Mark } from 'slate'
|
||||
|
||||
export default function(editor) {
|
||||
const marks = []
|
||||
|
||||
marks.push(
|
||||
editor.addMarks([
|
||||
Mark.create({
|
||||
type: 'bold',
|
||||
data: { thing: 'value' },
|
||||
})
|
||||
)
|
||||
|
||||
marks.push(
|
||||
}),
|
||||
Mark.create({
|
||||
type: 'italic',
|
||||
data: { thing2: 'value2' },
|
||||
})
|
||||
)
|
||||
|
||||
editor.addMarks(marks)
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
export const input = (
|
||||
@@ -38,9 +31,10 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<i thing2="value2">
|
||||
<b thing="value">w</b>
|
||||
<b thing="value">
|
||||
<anchor />w
|
||||
</b>
|
||||
</i>
|
||||
<focus />ord
|
||||
</paragraph>
|
||||
|
@@ -3,19 +3,17 @@
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
const marks = []
|
||||
editor.addMarks([
|
||||
{
|
||||
type: 'bold',
|
||||
data: { thing: 'value' },
|
||||
},
|
||||
|
||||
marks.push({
|
||||
type: 'bold',
|
||||
data: { thing: 'value' },
|
||||
})
|
||||
|
||||
marks.push({
|
||||
type: 'italic',
|
||||
data: { thing2: 'value2' },
|
||||
})
|
||||
|
||||
editor.addMarks(marks)
|
||||
{
|
||||
type: 'italic',
|
||||
data: { thing2: 'value2' },
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
export const input = (
|
||||
@@ -32,9 +30,10 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<i thing2="value2">
|
||||
<b thing="value">w</b>
|
||||
<b thing="value">
|
||||
<anchor />w
|
||||
</b>
|
||||
</i>
|
||||
<focus />ord
|
||||
</paragraph>
|
||||
|
@@ -0,0 +1,35 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
editor.delete()
|
||||
}
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<b>
|
||||
<anchor />wo
|
||||
</b>
|
||||
rd
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
two<focus />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<b>
|
||||
<cursor />
|
||||
</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
@@ -0,0 +1,31 @@
|
||||
/** @jsx h */
|
||||
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
export default function(editor) {
|
||||
editor.delete()
|
||||
}
|
||||
|
||||
export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<b>
|
||||
<anchor />word<focus />
|
||||
</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
||||
|
||||
export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<b>
|
||||
<cursor />
|
||||
</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
)
|
@@ -2,10 +2,6 @@
|
||||
|
||||
import h from '../../../helpers/h'
|
||||
|
||||
/*
|
||||
* This test makes sure a normalization happens on insertText on expandedRange
|
||||
*/
|
||||
|
||||
export default function(editor) {
|
||||
editor.insertText('a')
|
||||
editor.insertText('b')
|
||||
|
@@ -13,9 +13,10 @@ export const input = (
|
||||
<anchor />
|
||||
<b>
|
||||
<i>wo</i>
|
||||
<focus />
|
||||
</b>
|
||||
<i>rd</i>
|
||||
<i>
|
||||
<focus />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -10,9 +10,10 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wor<anchor />
|
||||
<b>d</b>
|
||||
<focus />
|
||||
wor
|
||||
<b>
|
||||
<anchor />d<focus />
|
||||
</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -10,8 +10,10 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
w<anchor />
|
||||
<b>o</b>
|
||||
w
|
||||
<b>
|
||||
<anchor />o
|
||||
</b>
|
||||
<focus />rd
|
||||
</paragraph>
|
||||
</document>
|
||||
|
@@ -10,8 +10,10 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<anchor />
|
||||
<i>rd</i>
|
||||
wo
|
||||
<i>
|
||||
<anchor />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<i>an</i>
|
||||
@@ -25,8 +27,10 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wo<anchor />
|
||||
<b>rd</b>
|
||||
wo
|
||||
<b>
|
||||
<anchor />rd
|
||||
</b>
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<b>an</b>
|
||||
|
@@ -10,18 +10,22 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>
|
||||
wo<anchor />
|
||||
<i>rd</i>
|
||||
wo
|
||||
<i>
|
||||
<anchor />rd
|
||||
</i>
|
||||
</link>
|
||||
<i />
|
||||
<text />
|
||||
</paragraph>
|
||||
<paragraph>
|
||||
<i />
|
||||
<text />
|
||||
<link>
|
||||
<i>an</i>
|
||||
<focus />other
|
||||
</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
@@ -31,9 +35,12 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<text />
|
||||
<link>
|
||||
wo<anchor />
|
||||
<b>rd</b>
|
||||
wo
|
||||
<b>
|
||||
<anchor />rd
|
||||
</b>
|
||||
</link>
|
||||
<b />
|
||||
</paragraph>
|
||||
@@ -43,6 +50,7 @@ export const output = (
|
||||
<b>an</b>
|
||||
<focus />other
|
||||
</link>
|
||||
<text />
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -10,9 +10,8 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<i>
|
||||
wo<focus />rd
|
||||
<anchor />wo<focus />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
@@ -25,8 +24,9 @@ export const output = (
|
||||
<paragraph>
|
||||
<anchor />
|
||||
<b>wo</b>
|
||||
<focus />
|
||||
<i>rd</i>
|
||||
<i>
|
||||
<focus />rd
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
@@ -10,9 +10,10 @@ export const input = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wor<anchor />
|
||||
<i>d</i>
|
||||
<focus />
|
||||
wor
|
||||
<i>
|
||||
<anchor />d<focus />
|
||||
</i>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
@@ -22,9 +23,10 @@ export const output = (
|
||||
<value>
|
||||
<document>
|
||||
<paragraph>
|
||||
wor<anchor />
|
||||
<b>d</b>
|
||||
<focus />
|
||||
wor
|
||||
<b>
|
||||
<anchor />d<focus />
|
||||
</b>
|
||||
</paragraph>
|
||||
</document>
|
||||
</value>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user