diff --git a/docs/reference/slate/node.md b/docs/reference/slate/node.md index 2e759b270..12714b30e 100644 --- a/docs/reference/slate/node.md +++ b/docs/reference/slate/node.md @@ -364,3 +364,10 @@ Check whether the node has a descendant node by `path` or `key`. `hasNode(key: String) => Boolean` Check whether a node exists in the tree by `path` or `key`. + +### `isNodeInRange` + +`isNodeInRange(path: List|Array) => Boolean` +`isNodeInRange(key: String) => Boolean` + +Check whether a node is inside a `range`. This will return true for all [`Text`](./text.md) nodes inside the range and all ancestors of those [`Text`](./text.md) nodes up to this node. diff --git a/packages/slate/src/interfaces/element.js b/packages/slate/src/interfaces/element.js index 8d26005d0..e2d76c2fd 100644 --- a/packages/slate/src/interfaces/element.js +++ b/packages/slate/src/interfaces/element.js @@ -1636,6 +1636,31 @@ class ElementInterface { return object === 'inline' && first.object !== 'inline' } + /** + * Check whether a descendant node is inside a range. This will return true for all + * text nodes inside the range and all ancestors of those text nodes up to this node. + * + * @param {List|Key} path + * @param {Range} range + * @return {Node} + */ + + isNodeInRange(path, range) { + this.assertDescendant(path) + path = this.resolvePath(path) + range = this.resolveRange(range) + if (range.isUnset) return false + + const toStart = PathUtils.compare(path, range.start.path) + const toEnd = + range.start.key === range.end.key + ? toStart + : PathUtils.compare(path, range.end.path) + + const is = toStart !== -1 && toEnd !== 1 + return is + } + /** * Map all child nodes, updating them in their parents. This method is * optimized to not return a new node if no changes are made. diff --git a/packages/slate/test/models/node/is-node-in-range/block-above-using-key.js b/packages/slate/test/models/node/is-node-in-range/block-above-using-key.js new file mode 100644 index 000000000..b091f70ac --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/block-above-using-key.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('a', selection) +} + +export const output = false diff --git a/packages/slate/test/models/node/is-node-in-range/block-above.js b/packages/slate/test/models/node/is-node-in-range/block-above.js new file mode 100644 index 000000000..9209d16b6 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/block-above.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([0], selection) +} + +export const output = false diff --git a/packages/slate/test/models/node/is-node-in-range/block-below-using-key.js b/packages/slate/test/models/node/is-node-in-range/block-below-using-key.js new file mode 100644 index 000000000..d8cb8decc --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/block-below-using-key.js @@ -0,0 +1,38 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + five + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('k', selection) +} + +export const output = false diff --git a/packages/slate/test/models/node/is-node-in-range/block-below.js b/packages/slate/test/models/node/is-node-in-range/block-below.js new file mode 100644 index 000000000..a6759d9b9 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/block-below.js @@ -0,0 +1,38 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + five + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([4], selection) +} + +export const output = false diff --git a/packages/slate/test/models/node/is-node-in-range/first-block-inside-using-key.js b/packages/slate/test/models/node/is-node-in-range/first-block-inside-using-key.js new file mode 100644 index 000000000..01f769fa1 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/first-block-inside-using-key.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('c', selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/first-block-inside.js b/packages/slate/test/models/node/is-node-in-range/first-block-inside.js new file mode 100644 index 000000000..fa0fde294 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/first-block-inside.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([1], selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/first-text-inside-using-key.js b/packages/slate/test/models/node/is-node-in-range/first-text-inside-using-key.js new file mode 100644 index 000000000..4898a0d2d --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/first-text-inside-using-key.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('d', selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/first-text-inside.js b/packages/slate/test/models/node/is-node-in-range/first-text-inside.js new file mode 100644 index 000000000..bd15b9418 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/first-text-inside.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([1, 0], selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/last-block-inside-using-key.js b/packages/slate/test/models/node/is-node-in-range/last-block-inside-using-key.js new file mode 100644 index 000000000..8b4968820 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/last-block-inside-using-key.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('g', selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/last-block-inside.js b/packages/slate/test/models/node/is-node-in-range/last-block-inside.js new file mode 100644 index 000000000..6aecf2897 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/last-block-inside.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([3], selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/last-text-inside-using-key.js b/packages/slate/test/models/node/is-node-in-range/last-text-inside-using-key.js new file mode 100644 index 000000000..8796ac2f2 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/last-text-inside-using-key.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('j', selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/last-text-inside.js b/packages/slate/test/models/node/is-node-in-range/last-text-inside.js new file mode 100644 index 000000000..0096163ec --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/last-text-inside.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([3, 1], selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/text-above-using-key.js b/packages/slate/test/models/node/is-node-in-range/text-above-using-key.js new file mode 100644 index 000000000..736e48a6d --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/text-above-using-key.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('b', selection) +} + +export const output = false diff --git a/packages/slate/test/models/node/is-node-in-range/text-above.js b/packages/slate/test/models/node/is-node-in-range/text-above.js new file mode 100644 index 000000000..f1fc3785a --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/text-above.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([0, 0], selection) +} + +export const output = false diff --git a/packages/slate/test/models/node/is-node-in-range/text-below-using-key.js b/packages/slate/test/models/node/is-node-in-range/text-below-using-key.js new file mode 100644 index 000000000..d56c4330f --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/text-below-using-key.js @@ -0,0 +1,38 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + five + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('l', selection) +} + +export const output = false diff --git a/packages/slate/test/models/node/is-node-in-range/text-below.js b/packages/slate/test/models/node/is-node-in-range/text-below.js new file mode 100644 index 000000000..530dee811 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/text-below.js @@ -0,0 +1,38 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + five + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([4, 0], selection) +} + +export const output = false diff --git a/packages/slate/test/models/node/is-node-in-range/text-in-middle-inside-using-key.js b/packages/slate/test/models/node/is-node-in-range/text-in-middle-inside-using-key.js new file mode 100644 index 000000000..dea69471f --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/text-in-middle-inside-using-key.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange('f', selection) +} + +export const output = true diff --git a/packages/slate/test/models/node/is-node-in-range/text-in-middle-inside.js b/packages/slate/test/models/node/is-node-in-range/text-in-middle-inside.js new file mode 100644 index 000000000..dfde7b784 --- /dev/null +++ b/packages/slate/test/models/node/is-node-in-range/text-in-middle-inside.js @@ -0,0 +1,35 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export const input = ( + + + + one + + + + two + + + + + + + + three + + + four + + + + +) + +export default function({ document, selection }) { + return document.isNodeInRange([2, 0], selection) +} + +export const output = true