1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-31 02:49:56 +02:00

fix offset calculations and splitting near inlines

This commit is contained in:
Ian Storm Taylor
2016-12-01 14:26:45 -08:00
parent 623b1f17b3
commit efd884b4b1
10 changed files with 168 additions and 65 deletions

View File

@@ -987,7 +987,13 @@ const Node = {
*/
getTextAtOffset(offset) {
// PERF: Add a few shortcuts for the obvious cases.
if (offset == 0) return this.getFirstText()
if (offset == this.length) return this.getLastText()
if (offset < 0 || offset > this.length) return null
let length = 0
return this
.getTexts()
.find((text, i, texts) => {
@@ -998,7 +1004,7 @@ const Node = {
// the furthest text node at the offset, and it will also match.
if (next && next.length == 0) return false
return length >= offset
return length > offset
})
},
@@ -1332,6 +1338,7 @@ const Node = {
let one
let two
if (node.kind != 'text') {
child = node.getTextAtOffset(offset)
}

View File

@@ -399,67 +399,48 @@ function setSelection(state, operation) {
function splitNode(state, operation) {
const { path, offset, count } = operation
const { document } = state
let { document, selection } = state
if (offset === undefined) {
return state.merge({
document: document.splitNodeAfter(path, count)
// No need to update selection
})
}
else {
// Update document
let newDocument = document.splitNode(path, offset)
// Update selection
let { selection } = state
const { anchorKey, anchorOffset, focusKey, focusOffset } = selection
const node = document.assertPath(path)
// The text node that was split
const splittedText = node.kind == 'text'
? node
: node.getTextAtOffset(offset)
const textOffset = node.kind == 'text'
? offset
: offset - node.getOffset(splittedText.key)
// Should we update the selection ?
const shouldUpdateAnchor = splittedText.key == anchorKey && textOffset <= anchorOffset
const shouldUpdateFocus = splittedText.key == focusKey && textOffset <= focusOffset
if (shouldUpdateFocus || shouldUpdateAnchor) {
// The node next to `node`, resulting from the split
const secondNode = newDocument.getNextSibling(node.key)
let secondText, newOffset
if (shouldUpdateAnchor) {
newOffset = anchorOffset - textOffset
secondText = secondNode.kind == 'text'
? secondNode
: secondNode.getTextAtOffset(newOffset)
selection = selection.merge({
anchorKey: secondText.key,
anchorOffset: newOffset
})
}
if (shouldUpdateFocus) {
newOffset = focusOffset - textOffset
secondText = secondNode.kind == 'text'
? secondNode
: secondNode.getTextAtOffset(newOffset)
selection = selection.merge({
focusKey: secondText.key,
focusOffset: newOffset
})
}
}
state = state.merge({
document: newDocument,
selection
})
// If there's no offset, it's using the `count` instead.
if (offset == null) {
document = document.splitNodeAfter(path, count)
state = state.merge({ document })
return state
}
// Otherwise, split using the `offset`, but calculate a few things first.
const node = document.assertPath(path)
const text = node.kind == 'text' ? node : node.getTextAtOffset(offset)
const textOffset = node.kind == 'text' ? offset : offset - node.getOffset(text.key)
const { anchorKey, anchorOffset, focusKey, focusOffset } = selection
document = document.splitNode(path, offset)
// Determine whether we need to update the selection.
const splitAnchor = text.key == anchorKey && textOffset <= anchorOffset
const splitFocus = text.key == focusKey && textOffset <= focusOffset
debugger
// If either the anchor of focus was after the split, we need to update them.
if (splitFocus || splitAnchor) {
const nextText = document.getNextText(text.key)
if (splitAnchor) {
selection = selection.merge({
anchorKey: nextText.key,
anchorOffset: anchorOffset - textOffset
})
}
if (splitFocus) {
selection = selection.merge({
focusKey: nextText.key,
focusOffset: focusOffset - textOffset
})
}
}
state = state.merge({ document, selection })
return state
}

View File

@@ -842,13 +842,16 @@ export function unwrapBlockAtRange(transform, range, properties, options = {}) {
transform.splitNodeByKey(block.key, offset, OPTS)
state = transform.state
document = state.document
const extra = document.getPreviousSibling(firstMatch.key)
children.forEach((child, i) => {
if (i == 0) {
const extra = child
child = document.getNextBlock(child.key)
transform.removeNodeByKey(extra.key, OPTS)
}
transform.moveNodeByKey(child.key, parent.key, index + 1 + i, OPTS)
})
transform.removeNodeByKey(extra.key, OPTS)
}
})

View File

@@ -0,0 +1,29 @@
import assert from 'assert'
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const third = texts.get(2)
const range = selection.merge({
anchorKey: third.key,
anchorOffset: 0,
focusKey: third.key,
focusOffset: 0
})
const next = state
.transform()
.moveTo(range)
.splitBlock()
.apply()
const updated = next.document.getTexts().get(2)
assert.deepEqual(
next.selection.toJS(),
range.collapseToStartOf(updated).toJS()
)
return next
}

View File

@@ -0,0 +1,16 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word
- kind: inline
type: link
data:
href: 'website.com'
nodes:
- kind: text
text: hyperlink
- kind: text
text: word

View File

@@ -0,0 +1,19 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word
- kind: inline
type: link
data:
href: 'website.com'
nodes:
- kind: text
text: hyperlink
- kind: block
type: paragraph
nodes:
- kind: text
text: word

View File

@@ -19,9 +19,11 @@ export default function (state) {
.unwrapBlock('quote')
.apply()
const updated = next.document.getTexts().get(2)
assert.deepEqual(
next.selection.toJS(),
range.toJS()
range.merge({ anchorKey: updated.key }).toJS()
)
return next

View File

@@ -0,0 +1,17 @@
export default function (state) {
const { document, selection } = state
const texts = document.getTexts()
const third = texts.get(2)
const range = selection.merge({
anchorKey: third.key,
anchorOffset: 0,
focusKey: third.key,
focusOffset: 0
})
return state
.transform()
.splitBlockAtRange(range)
.apply()
}

View File

@@ -0,0 +1,12 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word
- kind: inline
type: emoji
isVoid: true
- kind: text
text: word

View File

@@ -0,0 +1,17 @@
nodes:
- kind: block
type: paragraph
nodes:
- kind: text
text: word
- kind: inline
type: emoji
isVoid: true
- kind: text
text: ""
- kind: block
type: paragraph
nodes:
- kind: text
text: word