1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-15 11:44:05 +02:00

fix to use index instead of start and end in offset keys

This commit is contained in:
Ian Storm Taylor
2016-07-22 12:03:55 -07:00
parent f1124b3441
commit ac59e94a15
7 changed files with 93 additions and 57 deletions

View File

@@ -379,8 +379,8 @@ class Content extends React.Component {
}
const { anchorNode, anchorOffset, focusNode, focusOffset } = native
const anchor = OffsetKey.findPoint(anchorNode, anchorOffset)
const focus = OffsetKey.findPoint(focusNode, focusOffset)
const anchor = OffsetKey.findPoint(anchorNode, anchorOffset, state)
const focus = OffsetKey.findPoint(focusNode, focusOffset, state)
state = state
.transform()

View File

@@ -14,11 +14,10 @@ class Leaf extends React.Component {
*/
static propTypes = {
end: React.PropTypes.number.isRequired,
index: React.PropTypes.number.isRequired,
marks: React.PropTypes.object.isRequired,
node: React.PropTypes.object.isRequired,
renderMark: React.PropTypes.func.isRequired,
start: React.PropTypes.number.isRequired,
state: React.PropTypes.object.isRequired,
text: React.PropTypes.string.isRequired
};
@@ -31,18 +30,19 @@ class Leaf extends React.Component {
*/
shouldComponentUpdate(props) {
const { start, end, node, state } = props
const { index, node, state } = props
const { selection } = state
const should = (
selection.hasEdgeBetween(node, start, end) ||
props.start != this.props.start ||
props.end != this.props.end ||
if (
props.index != this.props.index ||
props.text != this.props.text ||
props.marks != this.props.marks
)
) {
return true
}
return should
const { start, end } = OffsetKey.findBounds(node.key, index, state)
return selection.hasEdgeBetween(node, start, end)
}
componentDidMount() {
@@ -61,7 +61,8 @@ class Leaf extends React.Component {
if (!selection.isFocused) return
const { anchorOffset, focusOffset } = selection
const { node, start, end } = this.props
const { node, index } = this.props
const { start, end } = OffsetKey.findBounds(node.key, index, state)
// If neither matches, the selection doesn't start or end here, so exit.
const hasAnchor = selection.hasAnchorBetween(node, start, end)
@@ -119,11 +120,10 @@ class Leaf extends React.Component {
}
render() {
const { node, text, marks, start, end, renderMark } = this.props
const { node, index, text, marks, renderMark } = this.props
const offsetKey = OffsetKey.stringify({
key: node.key,
start,
end
index
})
const style = marks.reduce((memo, mark) => {

View File

@@ -84,16 +84,13 @@ class Text extends React.Component {
const { node, renderMark, state } = this.props
const text = range.text
const marks = range.marks
const start = offset
const end = offset + text.length
return (
<Leaf
key={`${node.key}-${index}`}
index={index}
state={state}
node={node}
start={start}
end={end}
text={text}
marks={marks}
renderMark={renderMark}

View File

@@ -62,12 +62,10 @@ class Void extends React.Component {
const child = node.getTexts().first()
const text = ''
const marks = Mark.createSet()
const start = 0
const end = 0
const index = 0
const offsetKey = OffsetKey.stringify({
key: child.key,
start,
end
index
})
return (
@@ -77,8 +75,7 @@ class Void extends React.Component {
key={offsetKey}
state={state}
node={child}
start={start}
end={end}
index={index}
text={text}
marks={marks}
/>

View File

@@ -1,6 +1,8 @@
import Character from './character'
import Mark from './mark'
import groupByMarks from '../utils/group-by-marks'
import memoize from '../utils/memoize'
import uid from '../utils/uid'
import { List, Record } from 'immutable'
@@ -101,6 +103,16 @@ class Text extends new Record(DEFAULTS) {
})
}
/**
* Get the characters grouped by marks.
*
* @return {List}
*/
getRanges() {
return groupByMarks(this.decorations || this.characters)
}
/**
* Remove characters from the text node from `start` to `end`.
*
@@ -152,6 +164,14 @@ class Text extends new Record(DEFAULTS) {
}
/**
* Memoize read methods.
*/
memoize(Text.prototype, [
'getRanges'
])
/**
* Export.
*/

View File

@@ -29,12 +29,12 @@ function memoize(object, properties) {
object[property] = function (...args) {
const keys = [property, ...args, LEAF]
const cache = this.cache = this.cache || new Map()
const cache = this.__cache = this.__cache || new Map()
if (cache.hasIn(keys)) return cache.getIn(keys)
const value = original.apply(this, args)
this.cache = cache.setIn(keys, value)
this.__cache = cache.setIn(keys, value)
return value
}
}

View File

@@ -3,7 +3,7 @@
* Offset key parser regex.
*/
const PARSER = /^(\w+)(?::(\d+)-(\d+))?$/
const PARSER = /^(\w+)(?:-(\d+))?$/
/**
* Offset key attribute name.
@@ -13,26 +13,51 @@ const ATTRIBUTE = 'data-offset-key'
const SELECTOR = `[${ATTRIBUTE}]`
/**
* From a `node`, find the closest parent's offset key.
* Find the start and end bounds from a node's `key` and `index`.
*
* @param {Node} node
* @param {String} key
* @param {Number} index
* @param {State} state
* @return {Object}
*/
function findBounds(key, index, state) {
const text = state.document.assertDescendant(key)
const ranges = text.getRanges()
const range = ranges.get(index)
const start = ranges
.slice(0, index)
.reduce((memo, r) => {
return memo += r.text.length
}, 0)
return {
start,
end: start + range.text.length
}
}
/**
* From a `element`, find the closest parent's offset key.
*
* @param {Element} element
* @return {String} key
*/
function findKey(node) {
if (node.nodeType == 3) node = node.parentNode
function findKey(element) {
if (element.nodeType == 3) element = element.parentNode
// If a parent with an offset key exists, use it.
const parent = node.closest(SELECTOR)
const parent = element.closest(SELECTOR)
if (parent) return parent.getAttribute(ATTRIBUTE)
// Otherwise, if a child with an offset key exists, use it.
const child = node.querySelector(SELECTOR)
const child = element.querySelector(SELECTOR)
if (child) return child.getAttribute(ATTRIBUTE)
// Otherwise, move up the tree looking for cousin offset keys in parents.
while (node = node.parentNode) {
const cousin = node.querySelector(SELECTOR)
while (element = element.parentNode) {
const cousin = element.querySelector(SELECTOR)
if (cousin) return cousin.getAttribute(ATTRIBUTE)
}
@@ -41,24 +66,26 @@ function findKey(node) {
}
/**
* From a `node` and `offset`, find the closest parent's point.
* Find the selection point from an `element`, `offset`, and list of `ranges`.
*
* @param {Node} node
* @param {Element} element
* @param {Offset} offset
* @param {State} state
* @return {String} key
*/
function findPoint(node, offset) {
const key = findKey(node)
const parsed = parse(key)
function findPoint(element, offset, state) {
const offsetKey = findKey(element)
const { key, index } = parse(offsetKey)
const { start, end } = findBounds(key, index, state)
// Don't let the offset be outside the start and end bounds.
offset = parsed.start + offset
offset = Math.max(offset, parsed.start)
offset = Math.min(offset, parsed.end)
// Don't let the offset be outside of the start and end bounds.
offset = start + offset
offset = Math.max(offset, start)
offset = Math.min(offset, end)
return {
key: parsed.key,
key,
offset
}
}
@@ -67,21 +94,16 @@ function findPoint(node, offset) {
* Parse an offset key `string`.
*
* @param {String} string
* @return {Object} parsed
* @return {Object}
*/
function parse(string) {
const matches = PARSER.exec(string)
if (!matches) throw new Error(`Invalid offset key string "${string}".`)
let [ original, key, start, end ] = matches
start = parseInt(start, 10)
end = parseInt(end, 10)
const [ original, key, index ] = matches
return {
key,
start,
end
index
}
}
@@ -90,13 +112,12 @@ function parse(string) {
*
* @param {Object} object
* @property {String} key
* @property {Number} start
* @property {Number} end
* @property {Number} index
* @return {String} key
*/
function stringify(object) {
return `${object.key}:${object.start}-${object.end}`
return `${object.key}-${object.index}`
}
/**
@@ -104,6 +125,7 @@ function stringify(object) {
*/
export default {
findBounds,
findKey,
findPoint,
parse,