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