From eda5c02e79c3ee2807b5abc51002ca72af5c6a93 Mon Sep 17 00:00:00 2001
From: DamareYoh <34608378+DamareYoh@users.noreply.github.com>
Date: Mon, 5 Feb 2018 10:16:55 -0800
Subject: [PATCH] Bugfix/undo merge node (#1594)
* fixed build for windows
* fixed issue where undo of merge node does not restore the node back to its original properties
* fixed lint issue
* updated operation docs for additional property on split_node and merge_node
* finished incomplete sentence in the docs.
* updated test to also verify data is restored
* renamed the 'original' property to 'properties' to be more consistent with similar operation interfaces, updated docs
* got rid of extra operations property.
* deserializing properties in merge_node and split_node, passing properties object in splitNodeByKey
* missed committing operations modles.
* updated operations.toJSON for new properties on merge_node and split_node
* fix linting error
* remove outdated comment.
* expanded check for split node inverse to include inline nodes
* partially revert update to test with deletion across inlines
---
docs/reference/slate/operation.md | 8 ++++---
packages/slate/src/changes/by-key.js | 12 ++++++++++
.../src/constants/operation-attributes.js | 2 ++
packages/slate/src/models/operation.js | 22 +++++++++++++++++++
packages/slate/src/operations/apply.js | 8 ++++++-
.../test/history/undo/delete-across-blocks.js | 8 ++++---
.../history/undo/delete-across-inlines.js | 4 ++--
7 files changed, 55 insertions(+), 9 deletions(-)
diff --git a/docs/reference/slate/operation.md b/docs/reference/slate/operation.md
index dbee26f88..cbc905b57 100644
--- a/docs/reference/slate/operation.md
+++ b/docs/reference/slate/operation.md
@@ -104,11 +104,12 @@ Insert a new `node` at `path`.
{
type: 'merge_node',
path: Array,
- position: Number
+ position: Number,
+ properties: Object,
}
```
-Merge the node at `path` with its previous sibling. The `position` refers to either the index in the child nodes of the previous sibling in the case of [`Block`](./block.md) or [`Inline`](./inline.md) nodes, and the index in the characters of the previous sibling in the case of [`Text`](./text.md) nodes.
+Merge the node at `path` with its previous sibling. The `position` refers to either the index in the child nodes of the previous sibling in the case of [`Block`](./block.md) or [`Inline`](./inline.md) nodes, and the index in the characters of the previous sibling in the case of [`Text`](./text.md) nodes. The `properties` object contains properties of the merged node in the event that the change is undone.
### `move_node`
@@ -155,10 +156,11 @@ Set new `properties` on the node at `path`.
path: Array,
position: Number,
target: Number,
+ properties: Object,
}
```
-Split the node at `path` at `position`. The `position` refers to either the index in the child nodes in the case of [`Block`](./block.md) or [`Inline`](./inline.md) nodes, and the index in the characters in the case of [`Text`](./text.md) nodes. In the case of nested splits, `target` refers to the target path of the child split operation.
+Split the node at `path` at `position`. The `position` refers to either the index in the child nodes in the case of [`Block`](./block.md) or [`Inline`](./inline.md) nodes, and the index in the characters in the case of [`Text`](./text.md) nodes. In the case of nested splits, `target` refers to the target path of the child split operation. The `properties` object contains properties that should be assigned to the new node created after the split operation is complete.
## Value Operations
diff --git a/packages/slate/src/changes/by-key.js b/packages/slate/src/changes/by-key.js
index 49f51e2f6..e9ac3a7d1 100644
--- a/packages/slate/src/changes/by-key.js
+++ b/packages/slate/src/changes/by-key.js
@@ -174,6 +174,7 @@ Changes.mergeNodeByKey = (change, key, options = {}) => {
const { value } = change
const { document } = value
const path = document.getPath(key)
+ const original = document.getDescendant(key)
const previous = document.getPreviousSibling(key)
if (!previous) {
@@ -187,6 +188,12 @@ Changes.mergeNodeByKey = (change, key, options = {}) => {
value,
path,
position,
+ // for undos to succeed we only need the type and data because
+ // these are the only properties that get changed in the merge operation
+ properties: {
+ type: original.type,
+ data: original.data,
+ },
target: null,
})
@@ -504,12 +511,17 @@ Changes.splitNodeByKey = (change, key, position, options = {}) => {
const { value } = change
const { document } = value
const path = document.getPath(key)
+ const node = document.getDescendantAtPath(path)
change.applyOperation({
type: 'split_node',
value,
path,
position,
+ properties: {
+ type: node.type,
+ data: node.data,
+ },
target,
})
diff --git a/packages/slate/src/constants/operation-attributes.js b/packages/slate/src/constants/operation-attributes.js
index 1a62f0bef..894848804 100644
--- a/packages/slate/src/constants/operation-attributes.js
+++ b/packages/slate/src/constants/operation-attributes.js
@@ -29,6 +29,7 @@ const OPERATION_ATTRIBUTES = {
'value',
'path',
'position',
+ 'properties',
'target',
],
move_node: [
@@ -82,6 +83,7 @@ const OPERATION_ATTRIBUTES = {
'value',
'path',
'position',
+ 'properties',
'target',
],
}
diff --git a/packages/slate/src/models/operation.js b/packages/slate/src/models/operation.js
index 8bb220a0c..2b10a4d1c 100644
--- a/packages/slate/src/models/operation.js
+++ b/packages/slate/src/models/operation.js
@@ -130,6 +130,10 @@ class Operation extends Record(DEFAULTS) {
v = Value.create(v)
}
+ if (key == 'properties' && type == 'merge_node') {
+ v = Node.createProperties(v)
+ }
+
if (key == 'properties' && type == 'set_mark') {
v = Mark.createProperties(v)
}
@@ -159,6 +163,10 @@ class Operation extends Record(DEFAULTS) {
v = Value.createProperties(v)
}
+ if (key == 'properties' && type == 'split_node') {
+ v = Node.createProperties(v)
+ }
+
attrs[key] = v
}
@@ -235,6 +243,13 @@ class Operation extends Record(DEFAULTS) {
value = value.toJSON()
}
+ if (key == 'properties' && type == 'merge_node') {
+ const v = {}
+ if ('data' in value) v.data = value.data.toJS()
+ if ('type' in value) v.type = value.type
+ value = v
+ }
+
if (key == 'properties' && type == 'set_mark') {
const v = {}
if ('data' in value) v.data = value.data.toJS()
@@ -270,6 +285,13 @@ class Operation extends Record(DEFAULTS) {
value = v
}
+ if (key == 'properties' && type == 'split_node') {
+ const v = {}
+ if ('data' in value) v.data = value.data.toJS()
+ if ('type' in value) v.type = value.type
+ value = v
+ }
+
json[key] = value
}
diff --git a/packages/slate/src/operations/apply.js b/packages/slate/src/operations/apply.js
index 9fe5a608e..6be000570 100644
--- a/packages/slate/src/operations/apply.js
+++ b/packages/slate/src/operations/apply.js
@@ -395,7 +395,7 @@ const APPLIERS = {
*/
split_node(value, operation) {
- const { path, position } = operation
+ const { path, position, properties } = operation
let { document, selection } = value
// Calculate a few things...
@@ -405,6 +405,12 @@ const APPLIERS = {
// Split the node by its parent.
parent = parent.splitNode(index, position)
+ if (properties) {
+ const splitNode = parent.nodes.get(index + 1)
+ if (splitNode.object !== 'text') {
+ parent = parent.updateNode(splitNode.merge(properties))
+ }
+ }
document = document.updateNode(parent)
// Determine whether we need to update the selection...
diff --git a/packages/slate/test/history/undo/delete-across-blocks.js b/packages/slate/test/history/undo/delete-across-blocks.js
index 40fa3db58..73b2ffedd 100644
--- a/packages/slate/test/history/undo/delete-across-blocks.js
+++ b/packages/slate/test/history/undo/delete-across-blocks.js
@@ -12,15 +12,17 @@ export default function (value) {
.value
}
+// the paragraph and code blocks have some random data
+// to verify that the data objects get restored to what they were after undo
export const input = (
-
+
one
-
+
two
-
+
)
diff --git a/packages/slate/test/history/undo/delete-across-inlines.js b/packages/slate/test/history/undo/delete-across-inlines.js
index 483df4994..bd84dae40 100644
--- a/packages/slate/test/history/undo/delete-across-inlines.js
+++ b/packages/slate/test/history/undo/delete-across-inlines.js
@@ -16,10 +16,10 @@ export const input = (
- one
+ one
- two
+ two