Skip to content

Commit 519a6de

Browse files
author
Zaydek Michels-Gualtieri
committed
Fixed several bugs with getRangeTypes
1 parent a1f716f commit 519a6de

File tree

7 files changed

+81
-88
lines changed

7 files changed

+81
-88
lines changed

src/Editor/useEditor/actions.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import addOrRemoveTypesOnSelection from "./addOrRemoveTypesOnSelection"
22
import deleteOnSelection from "./deleteOnSelection"
33
import extendRangeLTR from "./extendRangeLTR"
44
import extendRangeRTL from "./extendRangeRTL"
5-
import getIndexAtOffset from "./getIndexAtOffset"
5+
import getIndex from "./getIndex"
66
import getRangeTypes from "./getRangeTypes"
77
import getShorthandVars from "./getShorthandVars"
88
import insertHardParagraphAtCollapsed from "./insertHardParagraphAtCollapsed"
@@ -47,17 +47,17 @@ export function select(e, { range }) {
4747
// Clones the start text node or returns an empty text node.
4848
function cloneStartTextNode(e) {
4949
const { ch1 } = getShorthandVars(e)
50-
let textNode = {
51-
types: {},
52-
props: {
53-
children: "",
54-
},
50+
if (!ch1.length) {
51+
const textNode = {
52+
types: {},
53+
props: {
54+
children: "",
55+
},
56+
}
57+
return textNode
5558
}
56-
const x = getIndexAtOffset(ch1, e.range.start.offset + testForSelection(e))
57-
if (x >= 0) {
58-
textNode = JSONClone(ch1[x])
59-
}
60-
return textNode
59+
const x = getIndex(ch1, e.range.start.offset + testForSelection(e))
60+
return JSONClone(ch1[x])
6161
}
6262

6363
// Inserts text at the current range.

src/Editor/useEditor/createIndexAtOffset.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import JSONClone from "lib/JSON/JSONClone"
22
import textContent from "./textContent"
33

4-
// Non-idempotent function; creates an index for an offset.
5-
// See getIndexAtOffset for idempotent version.
4+
// TODO
65
function createIndexAtOffset(children, offset) {
76
// Eager returns:
87
if (!children.length) {

src/Editor/useEditor/getIndex.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import textContent from "./textContent"
2+
3+
// Creates a text node at a text offset and returns the node
4+
// offset for the created text node.
5+
6+
// Converts a text offset to a node offset.
7+
function getIndex(children, textOffset) {
8+
if (!children.length) {
9+
if (process.env.NODE_ENV !== "test") {
10+
throw new Error("FIXME")
11+
}
12+
return -1
13+
} else if (!textOffset) {
14+
return 0
15+
} else if (textOffset === textContent(children).length) {
16+
return children.length - 1
17+
}
18+
let nodeOffset = 0
19+
for (; nodeOffset < children.length; nodeOffset++) {
20+
if (textOffset - children[nodeOffset].props.children.length <= 0) {
21+
// No-op
22+
break
23+
}
24+
textOffset -= children[nodeOffset].props.children.length
25+
}
26+
return nodeOffset
27+
}
28+
29+
export default getIndex
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import getIndex from "./getIndex"
2+
3+
const children = [
4+
{ types: {}, props: { children: "Hello, " } },
5+
{ types: { code: {} }, props: { children: "world" } },
6+
{ types: {}, props: { children: "!" } },
7+
]
8+
9+
test("getIndex(...)", () => {
10+
expect(getIndex([], 0)).toBe(-1)
11+
expect(getIndex(children, 0)).toBe(0)
12+
expect(getIndex(children, 1)).toBe(0)
13+
expect(getIndex(children, 2)).toBe(0)
14+
expect(getIndex(children, 3)).toBe(0)
15+
expect(getIndex(children, 4)).toBe(0)
16+
expect(getIndex(children, 5)).toBe(0)
17+
expect(getIndex(children, 6)).toBe(0)
18+
expect(getIndex(children, 7)).toBe(0)
19+
expect(getIndex(children, 8)).toBe(1)
20+
expect(getIndex(children, 9)).toBe(1)
21+
expect(getIndex(children, 10)).toBe(1)
22+
expect(getIndex(children, 11)).toBe(1)
23+
expect(getIndex(children, 12)).toBe(1)
24+
expect(getIndex(children, 13)).toBe(2)
25+
})

src/Editor/useEditor/getIndexAtOffset.js

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/Editor/useEditor/getIndexAtOffset.test.js

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/Editor/useEditor/getRangeTypes.js

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,27 @@
1-
import getIndexAtOffset from "./getIndexAtOffset" // TODO
1+
import getIndex from "./getIndex" // TODO
22
import getShorthandVars from "./getShorthandVars"
33
import JSONClone from "lib/JSON/JSONClone"
44
import JSONEqual from "lib/JSON/JSONEqual"
55
import testForSelection from "./testForSelection"
66

7-
function getNextIndexAtOffset(children, offset) {
8-
if (!offset) {
9-
return 0
10-
}
11-
return getIndexAtOffset(children, offset) + 1
12-
}
13-
14-
// Gets text nodes from an array of elements.
15-
function getTextNodes(elements, range) {
7+
function aggregateOnSelection(elements, range) {
168
const ch = []
179
for (const each of elements) {
18-
if (!each.props.children.length) {
10+
const { key, props: { children } } = each
11+
12+
if (!children.length) {
1913
// No-op
2014
continue
2115
}
2216
let x1 = 0
23-
if (each.key === range.start.key) {
24-
x1 = getNextIndexAtOffset(each.props.children, range.start.offset)
17+
if (key === range.start.key) {
18+
x1 = getIndex(children, range.start.offset + 1)
2519
}
26-
let x2 = each.props.children.length
27-
if (each.key === range.end.key) {
28-
x2 = getNextIndexAtOffset(each.props.children, range.end.offset)
20+
let x2 = children.length
21+
if (key === range.end.key) {
22+
x2 = getIndex(children, range.end.offset)
2923
}
30-
// if (x1 === x2) {
31-
// x2++
32-
// }
33-
ch.push(...each.props.children.slice(x1, x2 + (x1 === x2)))
24+
ch.push(...children.slice(x1, x2 + 1))
3425
}
3526
return ch
3627
}
@@ -43,25 +34,24 @@ function getRangeTypes(e) {
4334
if (!ch1.length) {
4435
return {}
4536
}
46-
const x = getIndexAtOffset(ch1, e.range.start.offset)
37+
const x = getIndex(ch1, e.range.start.offset)
4738
return ch1[x].types
4839
}
4940

50-
const ch = getTextNodes(e.elements.slice(x1, x2 + 1), e.range)
41+
const ch = aggregateOnSelection(e.elements.slice(x1, x2 + 1), e.range)
5142
if (!ch.length) {
5243
return {}
5344
}
54-
5545
const clonedTypes = JSONClone(ch[0].types)
5646
const clonedTypesKeys = Object.keys(clonedTypes)
57-
for (const textNode of ch.slice(1)) { // Step over clonedTypes
47+
48+
for (const textNode of ch.slice(1)) { // Steps over ch[0]
5849
for (const key of clonedTypesKeys) {
5950
if (!textNode.types[key] || !JSONEqual(textNode.types[key], clonedTypes[key])) {
6051
delete clonedTypes[key]
6152
}
6253
}
6354
}
64-
6555
return clonedTypes
6656
}
6757

0 commit comments

Comments
 (0)