From fbe3980c17009e2c44d05757f40137b129fc135c Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 13 Sep 2016 11:10:05 -0700 Subject: [PATCH 1/6] fix delete-at-range across depths, closes #306 --- lib/transforms/at-range.js | 20 +++++++++---------- .../delete-at-range/across-depths/index.js | 18 +++++++++++++++++ .../delete-at-range/across-depths/input.yaml | 20 +++++++++++++++++++ .../delete-at-range/across-depths/output.yaml | 15 ++++++++++++++ 4 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 test/transforms/fixtures/at-range/delete-at-range/across-depths/index.js create mode 100644 test/transforms/fixtures/at-range/delete-at-range/across-depths/input.yaml create mode 100644 test/transforms/fixtures/at-range/delete-at-range/across-depths/output.yaml diff --git a/lib/transforms/at-range.js b/lib/transforms/at-range.js index af6899772..8e7646099 100644 --- a/lib/transforms/at-range.js +++ b/lib/transforms/at-range.js @@ -62,8 +62,8 @@ export function deleteAtRange(transform, range) { let { state } = transform let { document } = state let ancestor = document.getCommonAncestor(startKey, endKey) - const startChild = ancestor.getHighestChild(startKey) - const endChild = ancestor.getHighestChild(endKey) + let startChild = ancestor.getHighestChild(startKey) + let endChild = ancestor.getHighestChild(endKey) const startOff = startChild.getOffset(startKey) + startOffset const endOff = endChild.getOffset(endKey) + endOffset @@ -73,16 +73,16 @@ export function deleteAtRange(transform, range) { state = transform.state document = state.document ancestor = document.getCommonAncestor(startKey, endKey) - const startBlock = document.getClosestBlock(startKey) const endBlock = document.getClosestBlock(document.getNextText(endKey)) - const startIndex = ancestor.nodes.indexOf(startBlock) - const endIndex = ancestor.nodes.indexOf(endBlock) - const endLonelyParent = ancestor.getHighestChild(endBlock, (parent) => { - return parent.nodes.size == 1 - }) + startChild = ancestor.getHighestChild(startBlock) + endChild = ancestor.getHighestChild(endBlock) - ancestor.nodes.slice(startIndex + 1, endIndex).forEach((child) => { + const startIndex = ancestor.nodes.indexOf(startChild) + const endIndex = ancestor.nodes.indexOf(endChild) + const middles = ancestor.nodes.slice(startIndex + 1, endIndex) + + middles.forEach((child) => { transform.removeNodeByKey(child.key) }) @@ -92,7 +92,7 @@ export function deleteAtRange(transform, range) { transform.moveNodeByKey(child.key, newKey, newIndex) }) - transform.removeNodeByKey(endLonelyParent.key) + transform.removeNodeByKey(endChild.key) transform.normalizeDocument() return transform } diff --git a/test/transforms/fixtures/at-range/delete-at-range/across-depths/index.js b/test/transforms/fixtures/at-range/delete-at-range/across-depths/index.js new file mode 100644 index 000000000..3e1780eca --- /dev/null +++ b/test/transforms/fixtures/at-range/delete-at-range/across-depths/index.js @@ -0,0 +1,18 @@ + +export default function (state) { + const { document, selection } = state + const texts = document.getTexts() + const second = texts.get(1) + const third = texts.get(2) + const range = selection.merge({ + anchorKey: second.key, + anchorOffset: second.length, + focusKey: third.key, + focusOffset: 0 + }) + + return state + .transform() + .deleteAtRange(range) + .apply() +} diff --git a/test/transforms/fixtures/at-range/delete-at-range/across-depths/input.yaml b/test/transforms/fixtures/at-range/delete-at-range/across-depths/input.yaml new file mode 100644 index 000000000..630fadce6 --- /dev/null +++ b/test/transforms/fixtures/at-range/delete-at-range/across-depths/input.yaml @@ -0,0 +1,20 @@ + +nodes: + - kind: block + type: list + nodes: + - kind: block + type: item + nodes: + - kind: text + text: one + - kind: block + type: item + nodes: + - kind: text + text: two + - kind: block + type: paragraph + nodes: + - kind: text + text: three diff --git a/test/transforms/fixtures/at-range/delete-at-range/across-depths/output.yaml b/test/transforms/fixtures/at-range/delete-at-range/across-depths/output.yaml new file mode 100644 index 000000000..3c5d571f1 --- /dev/null +++ b/test/transforms/fixtures/at-range/delete-at-range/across-depths/output.yaml @@ -0,0 +1,15 @@ + +nodes: + - kind: block + type: list + nodes: + - kind: block + type: item + nodes: + - kind: text + text: one + - kind: block + type: item + nodes: + - kind: text + text: twothree From bcd85ff1bb47dac7ee900690d79e76f57db5baf8 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 13 Sep 2016 11:12:54 -0700 Subject: [PATCH 2/6] 0.14.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9303e461a..207a85d3f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "slate", "description": "A completely customizable framework for building rich text editors.", - "version": "0.14.2", + "version": "0.14.3", "license": "MIT", "repository": "git://github.com/ianstormtaylor/slate.git", "main": "./dist/index.js", From 7b55316c1850a59afc9c9417681f336cb042f717 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 13 Sep 2016 11:39:22 -0700 Subject: [PATCH 3/6] Fix insert fragment multiple nested (#309) * Add fixture for insertFragmentAtRange with multiple blocks in nested blocks * Small fix for the fixture's `expected` output * Rebase on master (0.14.x) Moved tests to new appropriate location * Output now expects that fragment are merged to adjacent blocks * fix insert fragment for multiple children --- lib/transforms/at-range.js | 2 +- .../fragment.yaml | 14 +++++++++++ .../index.js | 25 +++++++++++++++++++ .../input.yaml | 17 +++++++++++++ .../output.yaml | 20 +++++++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/fragment.yaml create mode 100644 test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/index.js create mode 100644 test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/input.yaml create mode 100644 test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/output.yaml diff --git a/lib/transforms/at-range.js b/lib/transforms/at-range.js index 8e7646099..22b122245 100644 --- a/lib/transforms/at-range.js +++ b/lib/transforms/at-range.js @@ -304,7 +304,7 @@ export function insertFragmentAtRange(transform, range, fragment) { fragment = fragment.removeDescendant(lonelyChild) fragment.nodes.forEach((node, i) => { - const newIndex = startIndex + i + 2 + const newIndex = startIndex + i + 1 transform.insertNodeByKey(parent.key, newIndex, node) }) } diff --git a/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/fragment.yaml b/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/fragment.yaml new file mode 100644 index 000000000..36c55f71a --- /dev/null +++ b/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/fragment.yaml @@ -0,0 +1,14 @@ + +nodes: + - kind: block + type: paragraph + nodes: + - kind: text + ranges: + - text: fragment one + - kind: block + type: paragraph + nodes: + - kind: text + ranges: + - text: fragment two diff --git a/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/index.js b/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/index.js new file mode 100644 index 000000000..8223d04db --- /dev/null +++ b/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/index.js @@ -0,0 +1,25 @@ + +import path from 'path' +import readMetadata from 'read-metadata' +import { Raw } from '../../../../../..' + +export default function (state) { + const file = path.resolve(__dirname, 'fragment.yaml') + const raw = readMetadata.sync(file) + const fragment = Raw.deserialize(raw, { terse: true }).document + + const { document, selection } = state + const texts = document.getTexts() + const first = texts.first() + const range = selection.merge({ + anchorKey: first.key, + anchorOffset: 2, + focusKey: first.key, + focusOffset: 2 + }) + + return state + .transform() + .insertFragmentAtRange(range, fragment) + .apply() +} diff --git a/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/input.yaml b/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/input.yaml new file mode 100644 index 000000000..dc4f410d2 --- /dev/null +++ b/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/input.yaml @@ -0,0 +1,17 @@ + +nodes: + - kind: block + type: list-item + nodes: + - kind: block + type: paragraph + nodes: + - kind: text + ranges: + - text: first + - kind: block + type: paragraph + nodes: + - kind: text + ranges: + - text: second diff --git a/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/output.yaml b/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/output.yaml new file mode 100644 index 000000000..afc27d3dc --- /dev/null +++ b/test/transforms/fixtures/at-range/insert-fragment-at-range/fragment-multiple-blocks-in-nested-block/output.yaml @@ -0,0 +1,20 @@ + +nodes: + - kind: block + type: list-item + nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: fifragment one + - kind: block + type: paragraph + nodes: + - kind: text + text: fragment tworst + - kind: block + type: paragraph + nodes: + - kind: text + text: second From 3ef82a3fbcf5a1408e44367440cbbc1cfcf811b7 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 13 Sep 2016 11:49:59 -0700 Subject: [PATCH 4/6] update docs for new node-level transforms --- docs/reference/models/transform.md | 57 +++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/docs/reference/models/transform.md b/docs/reference/models/transform.md index f66d6caa1..43085bd84 100644 --- a/docs/reference/models/transform.md +++ b/docs/reference/models/transform.md @@ -47,8 +47,16 @@ Transform methods can either operate on the [`Document`](./document.md), the [`S - [`moveTo`](#moveto) - [`move{Direction}`](#movedirection) - [Node Transforms](#node-transforms) - - [`removeNodeByKey`](#removeNodeByKey) - - [`setNodeByKey`](#setNodeByKey) + - [`addMarkByKey`](#addmarkbykey) + - [`insertNodeByKey`](#insertnodebykey) + - [`insertTextByKey`](#inserttextbykey) + - [`moveNodeByKey`](#movenodebykey) + - [`removeMarkByKey`](#removemarkbykey) + - [`removeNodeByKey`](#removenodebykey) + - [`removeTextByKey`](#removetextbykey) + - [`setMarkByKey`](#setmarkbykey) + - [`setNodeByKey`](#setnodebykey) + - [`splitNodeByKey`](#splitnodebykey) - [Document Transforms](#document-transforms) - [`deleteAtRange`](#deleteatrange) - [`deleteBackwardAtRange`](#deletebackwardatrange) @@ -258,17 +266,57 @@ Move the current selection to a selection with merged `properties`. The `propert ## Node Transforms +### `addMarkByKey` +`addMarkByKey(key: String, offset: Number, length: Number, mark: Mark) => Transform` + +Add a `mark` to `length` characters starting at an `offset` in a [`Node`](./node.md) by its `key`. + +### `insertNodeByKey` +`insertNodeByKey(key: String, index: Number, node: Node) => Transform` + +Insert a `node` at `index` inside a parent [`Node`](./node.md) by its `key`. + +### `insertTextByKey` +`insertTextByKey(key: String, offset: Number, text: String, [marks: Set]) => Transform` + +Insert `text` at an `offset` in a [`Node`](./node.md) with optional `marks`. + +### `moveNodeByKey` +`moveNodeByKey(key: String, newKey: String, newIndex: Number) => Transform` + +Move a [`Node`](./node.md) by its `key` to a new parent node with its `newKey` and at a `newIndex`. + +### `removeMarkByKey` +`removeMarkByKey(key: String, offset: Number, length: Number, mark: Mark) => Transform` + +Remove a `mark` from `length` characters starting at an `offset` in a [`Node`](./node.md) by its `key`. + ### `removeNodeByKey` `removeNodeByKey(key: String) => Transform` Remove a [`Node`](./node.md) from the document by its `key`. +### `removeTextByKey` +`removeTextByKey(key: String, offset: Number, length: Number) => Transform` + +Remove `length` characters of text starting at an `offset` in a [`Node`](./node.md) by its `key`. + +### `setMarkByKey` +`setMarkByKey(key: String, offset: Number, length: Number, mark: Mark, properties: Object) => Transform` + +Set a dictionary of `properties` on a [`mark`](./mark.md) on a [`Node`](./node.md) by its `key`. + ### `setNodeByKey` `setNodeByKey(key: String, properties: Object) => Transform`
`setNodeByKey(key: String, type: String) => Transform` Set a dictionary of `properties` on a [`Node`](./node.md) by its `key`. For convenience, you can pass a `type` string or `properties` object. +### `splitNodeByKey` +`splitNodeByKey(key: String, offset: Number) => Transform` + +Split a node by its `key` at an `offset`. + ## Document Transforms @@ -382,14 +430,15 @@ Wrap the [`Inline`](./inline.md) nodes in a `range` with a new [`Inline`](./inli Surround the text in a `range` with `prefix` and `suffix` strings. If the `suffix` is ommitted, the `prefix` will be used instead. + ## History Transforms ### `redo` -`redo() => State` +`redo() => Transfirn` Move forward one step in the history. ### `undo` -`undo() => State` +`undo() => Transfirn` Move backward one step in the history. From 5edbe3d9b7b492899747adce892e682061f507e3 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 13 Sep 2016 12:38:02 -0700 Subject: [PATCH 5/6] remove old, undocumented node-level mutating methods --- lib/models/node.js | 68 ---------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/lib/models/node.js b/lib/models/node.js index 0ad8e8836..155aa875c 100644 --- a/lib/models/node.js +++ b/lib/models/node.js @@ -932,46 +932,6 @@ const Node = { return !!this.getClosest(key, parent => parent.isVoid) }, - /** - * Insert child `nodes` after child by `key`. - * - * @param {String or Node} key - * @param {List} nodes - * @return {Node} node - */ - - insertChildrenAfter(key, nodes) { - const child = this.assertChild(key) - const index = this.nodes.indexOf(child) - - nodes = this.nodes - .slice(0, index + 1) - .concat(nodes) - .concat(this.nodes.slice(index + 1)) - - return this.merge({ nodes }) - }, - - /** - * Insert child `nodes` before child by `key`. - * - * @param {String or Node} key - * @param {List} nodes - * @return {Node} node - */ - - insertChildrenBefore(key, nodes) { - const child = this.assertChild(key) - const index = this.nodes.indexOf(child) - - nodes = this.nodes - .slice(0, index) - .concat(nodes) - .concat(this.nodes.slice(index)) - - return this.merge({ nodes }) - }, - /** * Insert a `node` at `index`. * @@ -1129,34 +1089,6 @@ const Node = { return node }, - /** - * Remove children after a child by `key`. - * - * @param {String or Node} key - * @return {Node} node - */ - - removeChildrenAfter(key) { - const child = this.assertChild(key) - const index = this.nodes.indexOf(child) - const nodes = this.nodes.slice(0, index + 1) - return this.merge({ nodes }) - }, - - /** - * Remove children after a child by `key`, including the child. - * - * @param {String or Node} key - * @return {Node} node - */ - - removeChildrenAfterIncluding(key) { - const child = this.assertChild(key) - const index = this.nodes.indexOf(child) - const nodes = this.nodes.slice(0, index) - return this.merge({ nodes }) - }, - /** * Remove a `node` from the children node map. * From 88f6ee5e12aa76b95a329ae075358f0e48b0e836 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 13 Sep 2016 12:38:14 -0700 Subject: [PATCH 6/6] fix typo in transform docs --- docs/reference/models/transform.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/models/transform.md b/docs/reference/models/transform.md index 43085bd84..44c6bd786 100644 --- a/docs/reference/models/transform.md +++ b/docs/reference/models/transform.md @@ -434,11 +434,11 @@ Surround the text in a `range` with `prefix` and `suffix` strings. If the `suffi ## History Transforms ### `redo` -`redo() => Transfirn` +`redo() => Transform` Move forward one step in the history. ### `undo` -`undo() => Transfirn` +`undo() => Transform` Move backward one step in the history.