diff --git a/packages/slate-react/src/plugins/after.js b/packages/slate-react/src/plugins/after.js index f4d762f85..9b81f6342 100644 --- a/packages/slate-react/src/plugins/after.js +++ b/packages/slate-react/src/plugins/after.js @@ -344,10 +344,11 @@ function AfterPlugin() { // Determine what the selection should be after changing the text. const delta = textContent.length - text.length const corrected = selection.collapseToEnd().move(delta) - const entire = selection + let entire = selection .moveAnchorTo(point.key, start) .moveFocusTo(point.key, end) - .normalize(document) + + entire = document.normalizeRange(entire) // Change the current value to have the leaf's text replaced. change.insertTextAtRange(entire, textContent, leaf.marks).select(corrected) @@ -583,7 +584,7 @@ function AfterPlugin() { if (next) range = range.moveFocusTo(next.key, 0) } - range = range.normalize(document) + range = document.normalizeRange(range) change.select(range) } diff --git a/packages/slate-react/src/utils/find-range.js b/packages/slate-react/src/utils/find-range.js index adfe1733e..07fa3dd1f 100644 --- a/packages/slate-react/src/utils/find-range.js +++ b/packages/slate-react/src/utils/find-range.js @@ -1,6 +1,5 @@ import getWindow from 'get-window' import isBackward from 'selection-is-backward' -import { Range } from 'slate' import { IS_IE, IS_EDGE } from 'slate-dev-environment' import findPoint from './find-point' @@ -60,7 +59,8 @@ function findRange(native, value) { } } - let range = Range.create({ + const { document } = value + const range = document.createRange({ anchorKey: anchor.key, anchorOffset: anchor.offset, focusKey: focus.key, @@ -69,7 +69,6 @@ function findRange(native, value) { isFocused: true, }) - range = range.normalize(value.document) return range } diff --git a/packages/slate-react/src/utils/get-event-range.js b/packages/slate-react/src/utils/get-event-range.js index 56d879a00..3999d6004 100644 --- a/packages/slate-react/src/utils/get-event-range.js +++ b/packages/slate-react/src/utils/get-event-range.js @@ -1,6 +1,5 @@ import getWindow from 'get-window' -import { Range } from 'slate' import findNode from './find-node' import findRange from './find-range' @@ -35,7 +34,7 @@ function getEventRange(event, value) { : y - rect.top < rect.top + rect.height - y const text = node.getFirstText() - const range = Range.create() + const range = document.createRange() if (isPrevious) { const previousText = document.getPreviousText(text.key) diff --git a/packages/slate/src/changes/by-path.js b/packages/slate/src/changes/by-path.js index af799ed78..eb72d6377 100644 --- a/packages/slate/src/changes/by-path.js +++ b/packages/slate/src/changes/by-path.js @@ -3,7 +3,6 @@ import Inline from '../models/inline' import Mark from '../models/mark' import Node from '../models/node' import PathUtils from '../utils/path-utils' -import Range from '../models/range' /** * Changes. @@ -343,12 +342,12 @@ Changes.replaceTextByPath = ( length = node.text.length - offset } - const range = Range.create({ + const range = document.createRange({ anchorPath: path, focusPath: path, anchorOffset: offset, focusOffset: offset + length, - }).normalize(document) + }) let activeMarks = document.getActiveMarksAtRange(range) @@ -358,7 +357,8 @@ Changes.replaceTextByPath = ( // 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; + // 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) ) diff --git a/packages/slate/src/changes/on-selection.js b/packages/slate/src/changes/on-selection.js index e75d3ea8b..2c0b4e318 100644 --- a/packages/slate/src/changes/on-selection.js +++ b/packages/slate/src/changes/on-selection.js @@ -25,7 +25,7 @@ Changes.select = (change, properties, options = {}) => { const { value } = change const { document, selection } = value const props = {} - const next = selection.merge(properties).normalize(document) + const next = document.createRange(selection.merge(properties)) // Re-compute the properties, to ensure that we get their normalized values. properties = pick(next, Object.keys(properties)) @@ -325,7 +325,7 @@ PROXY_TRANSFORMS.forEach(method => { const { value } = change const { document, selection } = value let next = selection[method](...args) - if (normalize) next = next.normalize(document) + if (normalize) next = document.createRange(next) change.select(next) } }) diff --git a/packages/slate/src/models/document.js b/packages/slate/src/models/document.js index e6b1eec5c..c03bdd73d 100644 --- a/packages/slate/src/models/document.js +++ b/packages/slate/src/models/document.js @@ -1,13 +1,9 @@ -/** - * Dependencies. - */ - import isPlainObject from 'is-plain-object' import logger from 'slate-dev-logger' import { List, Map, Record } from 'immutable' -import MODEL_TYPES, { isType } from '../constants/model-types' import KeyUtils from '../utils/key-utils' +import MODEL_TYPES, { isType } from '../constants/model-types' /** * Default properties. diff --git a/packages/slate/src/models/node.js b/packages/slate/src/models/node.js index ee0847a76..ae1caea1b 100644 --- a/packages/slate/src/models/node.js +++ b/packages/slate/src/models/node.js @@ -205,6 +205,19 @@ class Node { return ret } + /** + * Create a new range with `properties` relative to the node. + * + * @param {Object|Range} properties + * @return {Range} + */ + + createRange(properties) { + properties = Range.createProperties(properties) + const range = this.resolveRange(properties) + return range + } + /** * Recursively filter all descendant nodes with `iterator`. * @@ -275,7 +288,7 @@ class Node { */ getActiveMarksAtRange(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) return Set() if (range.isCollapsed) { @@ -397,7 +410,7 @@ class Node { */ getBlocksAtRangeAsArray(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) return [] const { startKey, endKey } = range @@ -465,7 +478,7 @@ class Node { */ getCharactersAtRange(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) return List() const { startKey, endKey, startOffset, endOffset } = range @@ -672,7 +685,7 @@ class Node { */ getFragmentAtRange(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) { return Document.create() @@ -839,7 +852,7 @@ class Node { */ getInlinesAtRangeAsArray(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) return [] const array = this.getTextsAtRangeAsArray(range) @@ -892,7 +905,7 @@ class Node { */ getInsertMarksAtRange(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) return Set() if (range.isCollapsed) { @@ -1178,7 +1191,7 @@ class Node { */ getOffsetAtRange(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) { throw new Error('The range cannot be unset to calculcate its offset.') @@ -1213,7 +1226,7 @@ class Node { */ getOrderedMarksAtRange(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) return OrderedSet() if (range.isCollapsed) { @@ -1537,7 +1550,7 @@ class Node { */ getTextsAtRange(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) return List() const { startKey, endKey } = range const list = new List( @@ -1555,7 +1568,7 @@ class Node { */ getTextsAtRangeAsArray(range) { - range = range.normalize(this) + range = this.resolveRange(range) if (range.isUnset) return [] const { startKey, endKey } = range const texts = this.getTextsBetweenPositionsAsArray(startKey, endKey) @@ -1835,6 +1848,18 @@ class Node { return ret } + /** + * Normalize the node with a `schema`. + * + * @param {Schema} schema + * @return {Function|Void} + */ + + normalize(schema) { + const normalizer = schema.normalizeNode(this) + return normalizer + } + /** * Attempt to "refind" a node by a previous `path`, falling back to looking * it up by `key` again. @@ -1977,6 +2002,20 @@ class Node { return path } + /** + * Resolve a `range`, relative to the node, ensuring that the keys and + * offsets in the range exist and that they are synced with the paths. + * + * @param {Range|Object} range + * @return {Range} + */ + + resolveRange(range) { + range = Range.create(range) + range = range.normalize(this) + return range + } + /** * Set `properties` on a node. * @@ -2046,17 +2085,6 @@ class Node { return ret } - /** - * Normalize the node with a `schema`. - * - * @param {Schema} schema - * @return {Function|Void} - */ - - normalize(schema) { - return schema.normalizeNode(this) - } - /** * Validate the node against a `schema`. * @@ -2138,7 +2166,7 @@ class Node { 'The `Node.isInRange` method is deprecated. Use the new `PathUtils.compare` helper instead.' ) - range = range.normalize(this) + range = this.resolveRange(range) const node = this const { startKey, endKey, isCollapsed } = range diff --git a/packages/slate/src/models/value.js b/packages/slate/src/models/value.js index 16355e8f7..d963032d6 100644 --- a/packages/slate/src/models/value.js +++ b/packages/slate/src/models/value.js @@ -119,7 +119,7 @@ class Value extends Record(DEFAULTS) { if (text) selection = selection.collapseToStartOf(text) } - selection = selection.normalize(document) + selection = document.createRange(selection) let value = new Value({ data, @@ -978,8 +978,8 @@ class Value extends Record(DEFAULTS) { setSelection(properties) { let value = this let { document, selection } = value - selection = selection.merge(properties) - selection = selection.normalize(document) + const next = selection.merge(properties) + selection = document.createRange(next) value = value.set('selection', selection) return value } @@ -1036,14 +1036,14 @@ class Value extends Record(DEFAULTS) { if (selection) { let next = selection.isSet ? iterator(selection) : selection if (!next) next = selection.deselect() - if (next !== selection) next = next.normalize(document) + if (next !== selection) next = document.createRange(next) value = value.set('selection', next) } if (decorations) { let next = decorations.map(decoration => { let n = decoration.isSet ? iterator(decoration) : decoration - if (n && n !== decoration) n = n.normalize(document) + if (n && n !== decoration) n = document.createRange(n) return n })