diff --git a/packages/slate/src/changes/by-key.js b/packages/slate/src/changes/by-key.js index 2504a983d..67862b02a 100644 --- a/packages/slate/src/changes/by-key.js +++ b/packages/slate/src/changes/by-key.js @@ -2,6 +2,7 @@ import Block from '../models/block' import Inline from '../models/inline' import Mark from '../models/mark' import Node from '../models/node' +import Range from '../models/range' /** * Changes. @@ -346,6 +347,71 @@ Changes.removeNodeByKey = (change, key, options = {}) => { } } +/** + * Insert `text` at `offset` in node by `key`. + * + * @param {Change} change + * @param {String} key + * @param {String} text + * @param {Set} marks (optional) + * @param {Object} options + * @property {Boolean} normalize + */ + +Changes.setTextByKey = (change, key, text, marks, options = {}) => { + const textNode = change.value.document.getDescendant(key) + change.replaceTextByKey(key, 0, textNode.text.length, text, marks, options) +} + +/** + * Replace A Length of Text with another string or text + * @param {Change} change + * @param {String} key + * @param {Number} offset + * @param {Number} length + * @param {string} text + * @param {Set} marks (optional) + * @param {Object} options + * @property {Boolean} normalize + * + */ + +Changes.replaceTextByKey = ( + change, + key, + offset, + length, + text, + marks, + options +) => { + const { document } = change.value + const textNode = document.getDescendant(key) + if (length + offset > textNode.text.length) { + length = textNode.text.length - offset + } + const range = Range.create({ + anchorKey: key, + focusKey: key, + anchorOffset: offset, + focusOffset: offset + length, + }) + let activeMarks = document.getActiveMarksAtRange(range) + + change.removeTextByKey(key, offset, length, { normalize: false }) + 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) + } + change.insertTextByKey(key, offset, text, marks, options) +} + /** * Remove text at `offset` and `length` in node by `key`. * diff --git a/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-active-marks-with-data.js b/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-active-marks-with-data.js new file mode 100644 index 000000000..1d9b8fcaa --- /dev/null +++ b/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-active-marks-with-data.js @@ -0,0 +1,36 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default function(change) { + const { anchorKey, anchorOffset } = change.value + change.replaceTextByKey(anchorKey, anchorOffset, 3, 'cat is cute', [ + { type: 'font-size', data: { size: 16 } }, + ]) +} + +export const input = ( + + + + Meow,{' '} + + word. + + + + +) + +export const output = ( + + + + Meow, cat is cute + + d. + + + + +) diff --git a/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-active-marks.js b/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-active-marks.js new file mode 100644 index 000000000..f8c2941a2 --- /dev/null +++ b/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-active-marks.js @@ -0,0 +1,34 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default function(change) { + const { anchorKey, anchorOffset } = change.value + change.replaceTextByKey(anchorKey, anchorOffset, 3, 'cat is cute') +} + +export const input = ( + + + + Meow,{' '} + + word. + + + + +) + +export const output = ( + + + + Meow,{' '} + + cat is cuted. + + + + +) diff --git a/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-mark-and-active-mark.js b/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-mark-and-active-mark.js new file mode 100644 index 000000000..54f65cd60 --- /dev/null +++ b/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-mark-and-active-mark.js @@ -0,0 +1,39 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default function(change) { + const { anchorKey, anchorOffset } = change.value + change.replaceTextByKey(anchorKey, anchorOffset, 3, 'cat is cute', [ + { type: 'italic' }, + ]) +} + +export const input = ( + + + + Meow,{' '} + + word. + + + + +) + +export const output = ( + + + + Meow,{' '} + + + cat is cute + + + d. + + + +) diff --git a/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-node-index-mark.js b/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-node-index-mark.js new file mode 100644 index 000000000..a91b3a92a --- /dev/null +++ b/packages/slate/test/changes/by-key/replace-text-by-key/replace-with-node-index-mark.js @@ -0,0 +1,30 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default function(change) { + const { anchorKey, anchorOffset } = change.value + change.replaceTextByKey(anchorKey, anchorOffset, 3, 'cat is cute') +} + +export const input = ( + + + + Meow, + word. + + + +) + +export const output = ( + + + + Meow, + cat is cuted. + + + +) diff --git a/packages/slate/test/changes/by-key/replace-text-by-key/replace-without-any-marks.js b/packages/slate/test/changes/by-key/replace-text-by-key/replace-without-any-marks.js new file mode 100644 index 000000000..63dbe3b16 --- /dev/null +++ b/packages/slate/test/changes/by-key/replace-text-by-key/replace-without-any-marks.js @@ -0,0 +1,28 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default function(change) { + const { anchorKey, anchorOffset } = change.value + change.replaceTextByKey(anchorKey, anchorOffset, 3, 'cat is cute') +} + +export const input = ( + + + + Meow, word. + + + +) + +export const output = ( + + + + Meow, cat is cuted. + + + +) diff --git a/packages/slate/test/changes/by-key/set-text-by-key/replace-with-string-and-mark.js b/packages/slate/test/changes/by-key/set-text-by-key/replace-with-string-and-mark.js new file mode 100644 index 000000000..271275003 --- /dev/null +++ b/packages/slate/test/changes/by-key/set-text-by-key/replace-with-string-and-mark.js @@ -0,0 +1,33 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default function(change) { + change.setTextByKey(change.value.anchorKey, 'cat is cute', [ + { type: 'bold' }, + { type: 'italic' }, + ]) +} + +export const input = ( + + + + word + + + +) + +export const output = ( + + + + + cat is cute + + + + + +) diff --git a/packages/slate/test/changes/by-key/set-text-by-key/replace-with-string.js b/packages/slate/test/changes/by-key/set-text-by-key/replace-with-string.js new file mode 100644 index 000000000..153305ea7 --- /dev/null +++ b/packages/slate/test/changes/by-key/set-text-by-key/replace-with-string.js @@ -0,0 +1,27 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default function(change) { + change.setTextByKey(change.value.anchorKey, 'cat is cute') +} + +export const input = ( + + + + word + + + +) + +export const output = ( + + + + cat is cute + + + +) diff --git a/packages/slate/test/helpers/h.js b/packages/slate/test/helpers/h.js index c6e1b13aa..4d43662f7 100644 --- a/packages/slate/test/helpers/h.js +++ b/packages/slate/test/helpers/h.js @@ -32,6 +32,7 @@ const h = createHyperscript({ b: 'bold', i: 'italic', u: 'underline', + fontSize: 'font-size', }, })