mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-18 05:01:17 +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:
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,46 +9,30 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"With Slate you can build complex block types that have their own embedded content and behaviors, like rendering checkboxes inside check list items!"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"With Slate you can build complex block types that have their own embedded content and behaviors, like rendering checkboxes inside check list items!"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "block",
|
||||
"type": "check-list-item",
|
||||
"data": {
|
||||
"checked": true
|
||||
},
|
||||
"data": { "checked": true },
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Slide to the left."
|
||||
}
|
||||
]
|
||||
"text": "Slide to the left."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "block",
|
||||
"type": "check-list-item",
|
||||
"data": {
|
||||
"checked": true
|
||||
},
|
||||
"data": { "checked": true },
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Slide to the right."
|
||||
}
|
||||
]
|
||||
"text": "Slide to the right."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -59,28 +45,18 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Criss-cross."
|
||||
}
|
||||
]
|
||||
"text": "Criss-cross."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "block",
|
||||
"type": "check-list-item",
|
||||
"data": {
|
||||
"checked": true
|
||||
},
|
||||
"data": { "checked": true },
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Criss-cross!"
|
||||
}
|
||||
]
|
||||
"text": "Criss-cross!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -93,11 +69,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Cha cha real smooth…"
|
||||
}
|
||||
]
|
||||
"text": "Cha cha real smooth…"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -110,11 +82,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Let's go to work!"
|
||||
}
|
||||
]
|
||||
"text": "Let's go to work!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -124,11 +92,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"There are certain behaviors that require rendering dynamic marks on string of text, like rendering code highlighting. For example:"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"There are certain behaviors that require rendering dynamic marks on string of text, like rendering code highlighting. For example:"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -29,11 +27,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "// A simple FizzBuzz implementation."
|
||||
}
|
||||
]
|
||||
"text": "// A simple FizzBuzz implementation."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -43,11 +37,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "for (var i = 1; i <= 100; i++) {"
|
||||
}
|
||||
]
|
||||
"text": "for (var i = 1; i <= 100; i++) {"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -57,11 +47,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " if (i % 15 == 0) {"
|
||||
}
|
||||
]
|
||||
"text": " if (i % 15 == 0) {"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -71,11 +57,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " console.log('Fizz Buzz');"
|
||||
}
|
||||
]
|
||||
"text": " console.log('Fizz Buzz');"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -85,11 +67,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " } else if (i % 5 == 0) {"
|
||||
}
|
||||
]
|
||||
"text": " } else if (i % 5 == 0) {"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -99,11 +77,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " console.log('Buzz');"
|
||||
}
|
||||
]
|
||||
"text": " console.log('Buzz');"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -113,11 +87,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " } else if (i % 3 == 0) {"
|
||||
}
|
||||
]
|
||||
"text": " } else if (i % 3 == 0) {"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -127,11 +97,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " console.log('Fizz');"
|
||||
}
|
||||
]
|
||||
"text": " console.log('Fizz');"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -141,11 +107,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " } else {"
|
||||
}
|
||||
]
|
||||
"text": " } else {"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -155,11 +117,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " console.log(i);"
|
||||
}
|
||||
]
|
||||
"text": " console.log(i);"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -169,11 +127,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": " }"
|
||||
}
|
||||
]
|
||||
"text": " }"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -183,11 +137,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "}"
|
||||
}
|
||||
]
|
||||
"text": "}"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -199,11 +149,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,14 +9,14 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{ "text": "Insert Text: ", "marks": [{ "type": "bold" }] },
|
||||
{
|
||||
"text":
|
||||
"Type 'cat' before every word 'before' and after every word 'after' and in the middle of the word 'pion' so that it says 'pi cat on' using the virtual keyboard",
|
||||
"marks": [{ "type": "italic" }]
|
||||
}
|
||||
]
|
||||
"text": "Insert Text: ",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text":
|
||||
"Type 'cat' before every word 'before' and after every word 'after' and in the middle of the word 'pion' so that it says 'pi cat on' using the virtual keyboard",
|
||||
"marks": [{ "type": "italic" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -24,11 +26,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Before there before is pion at after for after"
|
||||
}
|
||||
]
|
||||
"text": "Before there before is pion at after for after"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -38,14 +36,14 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{ "text": "Handle Enter: ", "marks": [{ "type": "bold" }] },
|
||||
{
|
||||
"text":
|
||||
"Hit Enter twice before every word 'before' and after every word 'after' and in the middle of the word 'split'",
|
||||
"marks": [{ "type": "italic" }]
|
||||
}
|
||||
]
|
||||
"text": "Handle Enter: ",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text":
|
||||
"Hit Enter twice before every word 'before' and after every word 'after' and in the middle of the word 'split'",
|
||||
"marks": [{ "type": "italic" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -55,11 +53,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Before there before is split at after for after"
|
||||
}
|
||||
]
|
||||
"text": "Before there before is split at after for after"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -69,20 +63,18 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Since it's rich text, you can do things like turn a selection of text "
|
||||
},
|
||||
{
|
||||
"text": "bold",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"text":
|
||||
", or add a semantically rendered block quote in the middle of the page, like this:"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Since it's rich text, you can do things like turn a selection of text "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "bold",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text":
|
||||
", or add a semantically rendered block quote in the middle of the page, like this:"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -92,11 +84,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "A wise quote."
|
||||
}
|
||||
]
|
||||
"text": "A wise quote."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -106,11 +94,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"In addition to simple image nodes, you can actually create complex embedded nodes. For example, this one contains an input element that lets you change the video being rendered!"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"In addition to simple image nodes, you can actually create complex embedded nodes. For example, this one contains an input element that lets you change the video being rendered!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -29,12 +27,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Try it out! If you want another good video URL to try, go with: https://www.youtube.com/embed/6Ejga4kJUts"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Try it out! If you want another good video URL to try, go with: https://www.youtube.com/embed/6Ejga4kJUts"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,27 +9,17 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"In addition to block nodes, you can create inline void nodes, like "
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"In addition to block nodes, you can create inline void nodes, like "
|
||||
},
|
||||
{
|
||||
"object": "inline",
|
||||
"type": "emoji",
|
||||
"data": {
|
||||
"code": "😃"
|
||||
}
|
||||
"data": { "code": "😃" }
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "!"
|
||||
}
|
||||
]
|
||||
"text": "!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -38,9 +30,7 @@
|
||||
{
|
||||
"object": "inline",
|
||||
"type": "emoji",
|
||||
"data": {
|
||||
"code": "🍔"
|
||||
}
|
||||
"data": { "code": "🍔" }
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -50,11 +40,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "This example shows emojis in action."
|
||||
}
|
||||
]
|
||||
"text": "This example shows emojis in action."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,11 +9,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Enforce Your Layout!"
|
||||
}
|
||||
]
|
||||
"text": "Enforce Your Layout!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -21,12 +19,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"This example shows how to enforce your layout with schema-specific rules. This document will always have a title block at the top and at least one paragraph in the body. Try deleting them and see what happens!"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"This example shows how to enforce your layout with schema-specific rules. This document will always have a title block at the top and at least one paragraph in the body. Try deleting them and see what happens!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Slate editors save all changes to an internal \"history\" automatically, so you don't need to implement undo/redo yourself. And the editor automatically binds to the browser's default undo/redo keyboard shortcuts."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Slate editors save all changes to an internal \"history\" automatically, so you don't need to implement undo/redo yourself. And the editor automatically binds to the browser's default undo/redo keyboard shortcuts."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -22,12 +20,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Try it out for yourself! Make any changes you'd like then press \"cmd+z\"."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Try it out for yourself! Make any changes you'd like then press \"cmd+z\"."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,34 +9,25 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"This example shows how you can make a hovering menu appear above your content, which you can use to make text "
|
||||
},
|
||||
{
|
||||
"text": "bold",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": ", "
|
||||
},
|
||||
{
|
||||
"text": "italic",
|
||||
"marks": [
|
||||
{
|
||||
"type": "italic"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": ", or anything else you might want to do!"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"This example shows how you can make a hovering menu appear above your content, which you can use to make text "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "bold",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": ", "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "italic",
|
||||
"marks": [{ "type": "italic" }]
|
||||
},
|
||||
{
|
||||
"text": ", or anything else you might want to do!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -44,25 +37,16 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try it out yourself! Just "
|
||||
},
|
||||
{
|
||||
"text": "select any piece of text and the menu will appear",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
},
|
||||
{
|
||||
"type": "italic"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "."
|
||||
}
|
||||
]
|
||||
"text": "Try it out yourself! Just "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "select any piece of text and the menu will appear",
|
||||
"marks": [{ "type": "bold" }, { "type": "italic" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -23,14 +23,14 @@ for (let h = 0; h < HEADINGS; h++) {
|
||||
nodes.push({
|
||||
object: 'block',
|
||||
type: 'heading',
|
||||
nodes: [{ object: 'text', leaves: [{ text: faker.lorem.sentence() }] }],
|
||||
nodes: [{ object: 'text', text: faker.lorem.sentence() }],
|
||||
})
|
||||
|
||||
for (let p = 0; p < PARAGRAPHS; p++) {
|
||||
nodes.push({
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
nodes: [{ object: 'text', leaves: [{ text: faker.lorem.paragraph() }] }],
|
||||
nodes: [{ object: 'text', text: faker.lorem.paragraph() }],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"In addition to nodes that contain editable text, you can also create other types of nodes, like images or videos."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"In addition to nodes that contain editable text, you can also create other types of nodes, like images or videos."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -30,12 +28,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"This example shows images in action. It features two ways to add images. You can either add an image via the toolbar icon above, or if you want in on a little secret, copy an image URL to your keyboard and paste it anywhere in the editor!"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"This example shows images in action. It features two ways to add images. You can either add an image via the toolbar icon above, or if you want in on a little secret, copy an image URL to your keyboard and paste it anywhere in the editor!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,45 +9,35 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "This Slate editor records all of the "
|
||||
},
|
||||
{
|
||||
"text": "keyboard",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": ", "
|
||||
},
|
||||
{
|
||||
"text": "input",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": " and "
|
||||
},
|
||||
{
|
||||
"text": "selection",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text":
|
||||
" event that occur while using it, so you can debug the exact combination of events that is firing for particular editing behaviors."
|
||||
}
|
||||
]
|
||||
"text": "This Slate editor records all of the "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "keyboard",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": ", "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "input",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": " and "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "selection",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text":
|
||||
" event that occur while using it, so you can debug the exact combination of events that is firing for particular editing behaviors."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -55,12 +47,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"And this is a quote in case you need to try testing across block types."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"And this is a quote in case you need to try testing across block types."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -70,11 +58,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try it out!"
|
||||
}
|
||||
]
|
||||
"text": "Try it out!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"In addition to block nodes, you can create inline nodes, like "
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"In addition to block nodes, you can create inline nodes, like "
|
||||
},
|
||||
{
|
||||
"object": "inline",
|
||||
@@ -23,21 +21,13 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "hyperlinks"
|
||||
}
|
||||
]
|
||||
"text": "hyperlinks"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "!"
|
||||
}
|
||||
]
|
||||
"text": "!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -47,12 +37,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"This example shows hyperlinks in action. It features two ways to add links. You can either add a link via the toolbar icon above, or if you want in on a little secret, copy a URL to your keyboard and paste it while a range of text is selected."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"This example shows hyperlinks in action. It features two ways to add links. You can either add a link via the toolbar icon above, or if you want in on a little secret, copy a URL to your keyboard and paste it while a range of text is selected."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"The editor gives you full control over the logic you can add. For example, it's fairly common to want to add markdown-like shortcuts to editors. So that, when you start a line with \"> \" you get a blockquote that looks like this:"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"The editor gives you full control over the logic you can add. For example, it's fairly common to want to add markdown-like shortcuts to editors. So that, when you start a line with \"> \" you get a blockquote that looks like this:"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -22,11 +20,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "A wise quote."
|
||||
}
|
||||
]
|
||||
"text": "A wise quote."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -36,12 +30,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Order when you start a line with \"## \" you get a level-two heading, like this:"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Order when you start a line with \"## \" you get a level-two heading, like this:"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -51,11 +41,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try it out!"
|
||||
}
|
||||
]
|
||||
"text": "Try it out!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -65,12 +51,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Try it out for yourself! Try starting a new line with \">\", \"-\", or \"#\"s."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Try it out for yourself! Try starting a new line with \">\", \"-\", or \"#\"s."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,11 +9,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try mentioning some users, like Luke or Leia."
|
||||
}
|
||||
]
|
||||
"text": "Try mentioning some users, like Luke or Leia."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"By default, pasting content into a Slate editor will use the content's plain text representation. This is fine for some use cases, but sometimes you want to actually be able to paste in content and have it parsed into blocks and links and things. To do this, you need to add a parser that triggers on paste. This is an example of doing exactly that!"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"By default, pasting content into a Slate editor will use the content's plain text representation. This is fine for some use cases, but sometimes you want to actually be able to paste in content and have it parsed into blocks and links and things. To do this, you need to add a parser that triggers on paste. This is an example of doing exactly that!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -22,12 +20,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Try it out for yourself! Copy and paste some rendered HTML content (not the source code) from another site into this editor."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Try it out for yourself! Copy and paste some rendered HTML content (not the source code) from another site into this editor."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,7 +9,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": []
|
||||
"text": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"objcet": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,44 +9,34 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "This is editable "
|
||||
},
|
||||
{
|
||||
"text": "rich",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": " text, "
|
||||
},
|
||||
{
|
||||
"text": "much",
|
||||
"marks": [
|
||||
{
|
||||
"type": "italic"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": " better than a "
|
||||
},
|
||||
{
|
||||
"text": "<textarea>",
|
||||
"marks": [
|
||||
{
|
||||
"type": "code"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "!"
|
||||
}
|
||||
]
|
||||
"text": "This is editable "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "rich",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": " text, "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "much",
|
||||
"marks": [{ "type": "italic" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": " better than a "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "<textarea>",
|
||||
"marks": [{ "type": "code" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -54,24 +46,18 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Since it's rich text, you can do things like turn a selection of text "
|
||||
},
|
||||
{
|
||||
"text": "bold",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text":
|
||||
", or add a semantically rendered block quote in the middle of the page, like this:"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Since it's rich text, you can do things like turn a selection of text "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "bold",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text":
|
||||
", or add a semantically rendered block quote in the middle of the page, like this:"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -81,11 +67,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "A wise quote."
|
||||
}
|
||||
]
|
||||
"text": "A wise quote."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -95,11 +77,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Slate supports both left-to-right text editing (English, French, etc.) and right-to-left text editing (Arabic, Hebrew, etc.) which it automatically detects. Here's an example featuring excerpts from Khalil Gibran:"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Slate supports both left-to-right text editing (English, French, etc.) and right-to-left text editing (Arabic, Hebrew, etc.) which it automatically detects. Here's an example featuring excerpts from Khalil Gibran:"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -22,12 +20,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Et un jeune dit : parle-nous de l'amitié.\nEt il répondit, disant :\nVotre ami est votre besoin qui a trouvé une réponse.\nIl est le champ que vous semez avec amour et moissonnez avec reconnaissance.\nIl est votre table et votre foyer."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Et un jeune dit : parle-nous de l'amitié.\nEt il répondit, disant :\nVotre ami est votre besoin qui a trouvé une réponse.\nIl est le champ que vous semez avec amour et moissonnez avec reconnaissance.\nIl est votre table et votre foyer."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -37,12 +31,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"ثم قال له شاب: هات حدثناعن الصداقة.\nفأجاب و قال:\nإن صديقك هو كفاية حاجاتك.\nهو حقك الذي تزرعه بالمحبة و تحصده بالشكر.\nهو مائدتك و موقدك."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"ثم قال له شاب: هات حدثناعن الصداقة.\nفأجاب و قال:\nإن صديقك هو كفاية حاجاتك.\nهو حقك الذي تزرعه بالمحبة و تحصده بالشكر.\nهو مائدتك و موقدك."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -52,12 +42,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"And a youth said, \"Speak to us of Friendship.\"\nYour friend is your needs answered.\nHe is your field which you sow with love and reap with thanksgiving.\nAnd he is your board and your fireside."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"And a youth said, \"Speak to us of Friendship.\"\nYour friend is your needs answered.\nHe is your field which you sow with love and reap with thanksgiving.\nAnd he is your board and your fireside."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -67,11 +53,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
"text": "Try it out for yourself!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"This is editable text that you can search. As you search, it looks for matching strings of text, and adds \"decoration\" marks to them in realtime."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"This is editable text that you can search. As you search, it looks for matching strings of text, and adds \"decoration\" marks to them in realtime."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -22,12 +20,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Try it out for yourself by typing in the search box above!"
|
||||
}
|
||||
]
|
||||
"text": "Try it out for yourself by typing in the search box above!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,22 +9,16 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "These two editors are kept "
|
||||
},
|
||||
{
|
||||
"text": "in sync",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": " with one another as you type!"
|
||||
}
|
||||
]
|
||||
"text": "These two editors are kept "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "in sync",
|
||||
"marks": [{ "type": "bold" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": " with one another as you type!"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -32,23 +28,17 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"They achieve this by sending any document-altering operations to each other whenever a change occurs, and then applying them locally with "
|
||||
},
|
||||
{
|
||||
"text": "editor.applyOperation()",
|
||||
"marks": [
|
||||
{
|
||||
"type": "code"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"They achieve this by sending any document-altering operations to each other whenever a change occurs, and then applying them locally with "
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "editor.applyOperation()",
|
||||
"marks": [{ "type": "code" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text": "."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -58,20 +48,13 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Note: ",
|
||||
"marks": [
|
||||
{
|
||||
"type": "italic"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text":
|
||||
"this example doesn't showcase operational transforms or network communication, which are required for realtime editing with multiple people at once."
|
||||
}
|
||||
]
|
||||
"text": "Note: ",
|
||||
"marks": [{ "type": "italic" }]
|
||||
},
|
||||
{
|
||||
"object": "text",
|
||||
"text":
|
||||
"this example doesn't showcase operational transforms or network communication, which are required for realtime editing with multiple people at once."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"Since the editor is based on a recursive tree model, similar to an HTML document, you can create complex nested structures, like tables:"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"Since the editor is based on a recursive tree model, similar to an HTML document, you can create complex nested structures, like tables:"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -30,11 +28,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": ""
|
||||
}
|
||||
]
|
||||
"text": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -44,16 +38,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Human",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"text": "Human",
|
||||
"marks": [{ "type": "bold" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -63,16 +49,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Dog",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"text": "Dog",
|
||||
"marks": [{ "type": "bold" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -82,16 +60,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "Cat",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"text": "Cat",
|
||||
"marks": [{ "type": "bold" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -107,16 +77,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "# of Feet",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"text": "# of Feet",
|
||||
"marks": [{ "type": "bold" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -126,11 +88,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "2"
|
||||
}
|
||||
]
|
||||
"text": "2"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -140,11 +98,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "4"
|
||||
}
|
||||
]
|
||||
"text": "4"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -154,11 +108,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "4"
|
||||
}
|
||||
]
|
||||
"text": "4"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -174,16 +124,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "# of Lives",
|
||||
"marks": [
|
||||
{
|
||||
"type": "bold"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"text": "# of Lives",
|
||||
"marks": [{ "type": "bold" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -193,11 +135,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "1"
|
||||
}
|
||||
]
|
||||
"text": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -207,11 +145,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "1"
|
||||
}
|
||||
]
|
||||
"text": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -221,11 +155,7 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text": "9"
|
||||
}
|
||||
]
|
||||
"text": "9"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -239,12 +169,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"This table is just a basic example of rendering a table, and it doesn't have fancy functionality. But you could augment it to add support for navigating with arrow keys, displaying table headers, adding column and rows, or even formulas if you wanted to get really crazy!"
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"This table is just a basic example of rendering a table, and it doesn't have fancy functionality. But you could augment it to add support for navigating with arrow keys, displaying table headers, adding column and rows, or even formulas if you wanted to get really crazy!"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
@@ -7,12 +9,8 @@
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"leaves": [
|
||||
{
|
||||
"text":
|
||||
"This example shows how you might implement a version history, where you can save a new version after applying some changes, and then rollback to a previous version at any time."
|
||||
}
|
||||
]
|
||||
"text":
|
||||
"This example shows how you might implement a version history, where you can save a new version after applying some changes, and then rollback to a previous version at any time."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -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>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user