mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-23 07:22:55 +02:00
fix mark operation range creation
This commit is contained in:
@@ -28,15 +28,41 @@ Changes.addMarkByKey = (change, key, offset, length, mark, options = {}) => {
|
|||||||
const { state } = change
|
const { state } = change
|
||||||
const { document } = state
|
const { document } = state
|
||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
|
const node = document.getNode(key)
|
||||||
|
const ranges = node.getRanges()
|
||||||
|
|
||||||
change.applyOperation({
|
const operations = []
|
||||||
type: 'add_mark',
|
const bx = offset
|
||||||
path,
|
const by = offset + length
|
||||||
offset,
|
let o = 0
|
||||||
length,
|
|
||||||
mark,
|
ranges.forEach((range) => {
|
||||||
|
const ax = o
|
||||||
|
const ay = ax + range.text.length
|
||||||
|
|
||||||
|
o += range.text.length
|
||||||
|
|
||||||
|
// If the range doesn't overlap with the operation, continue on.
|
||||||
|
if (ay < bx || by < ax) return
|
||||||
|
|
||||||
|
// If the range already has the mark, continue on.
|
||||||
|
if (range.marks.has(mark)) return
|
||||||
|
|
||||||
|
// Otherwise, determine which offset and characters overlap.
|
||||||
|
const start = Math.max(ax, bx)
|
||||||
|
const end = Math.min(ay, by)
|
||||||
|
|
||||||
|
operations.push({
|
||||||
|
type: 'add_mark',
|
||||||
|
path,
|
||||||
|
offset: start,
|
||||||
|
length: end - start,
|
||||||
|
mark,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
change.applyOperations(operations)
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
change.normalizeNodeByKey(parent.key, SCHEMA)
|
change.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
@@ -211,15 +237,41 @@ Changes.removeMarkByKey = (change, key, offset, length, mark, options = {}) => {
|
|||||||
const { state } = change
|
const { state } = change
|
||||||
const { document } = state
|
const { document } = state
|
||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
|
const node = document.getNode(key)
|
||||||
|
const ranges = node.getRanges()
|
||||||
|
|
||||||
change.applyOperation({
|
const operations = []
|
||||||
type: 'remove_mark',
|
const bx = offset
|
||||||
path,
|
const by = offset + length
|
||||||
offset,
|
let o = 0
|
||||||
length,
|
|
||||||
mark,
|
ranges.forEach((range) => {
|
||||||
|
const ax = o
|
||||||
|
const ay = ax + range.text.length
|
||||||
|
|
||||||
|
o += range.text.length
|
||||||
|
|
||||||
|
// If the range doesn't overlap with the operation, continue on.
|
||||||
|
if (ay < bx || by < ax) return
|
||||||
|
|
||||||
|
// If the range already has the mark, continue on.
|
||||||
|
if (!range.marks.has(mark)) return
|
||||||
|
|
||||||
|
// Otherwise, determine which offset and characters overlap.
|
||||||
|
const start = Math.max(ax, bx)
|
||||||
|
const end = Math.min(ay, by)
|
||||||
|
|
||||||
|
operations.push({
|
||||||
|
type: 'remove_mark',
|
||||||
|
path,
|
||||||
|
offset: start,
|
||||||
|
length: end - start,
|
||||||
|
mark,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
change.applyOperations(operations)
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
change.normalizeNodeByKey(parent.key, SCHEMA)
|
change.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
@@ -280,7 +332,6 @@ Changes.removeTextByKey = (change, key, offset, length, options = {}) => {
|
|||||||
let o = 0
|
let o = 0
|
||||||
|
|
||||||
ranges.forEach((range) => {
|
ranges.forEach((range) => {
|
||||||
const { marks } = range
|
|
||||||
const ax = o
|
const ax = o
|
||||||
const ay = ax + range.text.length
|
const ay = ax + range.text.length
|
||||||
|
|
||||||
@@ -299,15 +350,12 @@ Changes.removeTextByKey = (change, key, offset, length, options = {}) => {
|
|||||||
path,
|
path,
|
||||||
offset: start,
|
offset: start,
|
||||||
text: string,
|
text: string,
|
||||||
marks,
|
marks: range.marks,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Apply the removals in reverse order, so that subsequent removals aren't
|
// Apply in reverse order, so subsequent removals don't impact previous ones.
|
||||||
// impacted by previous ones.
|
change.applyOperations(removals.reverse())
|
||||||
removals.reverse().forEach((op) => {
|
|
||||||
change.applyOperation(op)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const block = document.getClosestBlock(key)
|
const block = document.getClosestBlock(key)
|
||||||
|
@@ -13,11 +13,11 @@ export default function (state) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const next = state
|
const next = state
|
||||||
.transform()
|
.change()
|
||||||
.select(range)
|
.select(range)
|
||||||
.toggleMark('bold')
|
.toggleMark('bold')
|
||||||
.insertText('a')
|
.insertText('a')
|
||||||
.apply()
|
.state
|
||||||
|
|
||||||
assert.deepEqual(next.selection.toJS(), range.move(1).toJS())
|
assert.deepEqual(next.selection.toJS(), range.move(1).toJS())
|
||||||
|
|
@@ -13,10 +13,10 @@ export default function (state) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const next = state
|
const next = state
|
||||||
.transform()
|
.change()
|
||||||
.select(range)
|
.select(range)
|
||||||
.toggleMark('bold')
|
.toggleMark('bold')
|
||||||
.apply()
|
.state
|
||||||
|
|
||||||
assert.deepEqual(next.selection.toJS(), range.toJS())
|
assert.deepEqual(next.selection.toJS(), range.toJS())
|
||||||
|
|
@@ -12,10 +12,10 @@ export default function (state) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const next = state
|
const next = state
|
||||||
.transform()
|
.change()
|
||||||
.select(range)
|
.select(range)
|
||||||
.toggleMark('bold')
|
.toggleMark('bold')
|
||||||
.apply()
|
.state
|
||||||
|
|
||||||
assert.deepEqual(next.selection.toJS(), range.toJS())
|
assert.deepEqual(next.selection.toJS(), range.toJS())
|
||||||
|
|
@@ -13,12 +13,12 @@ export default function (state) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const next = state
|
const next = state
|
||||||
.transform()
|
.change()
|
||||||
.select(range)
|
.select(range)
|
||||||
.toggleMark('bold')
|
.toggleMark('bold')
|
||||||
.toggleMark('bold')
|
.toggleMark('bold')
|
||||||
.insertText('a')
|
.insertText('a')
|
||||||
.apply()
|
.state
|
||||||
|
|
||||||
assert.deepEqual(next.selection.toJS(), range.move(1).toJS())
|
assert.deepEqual(next.selection.toJS(), range.move(1).toJS())
|
||||||
|
|
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
import assert from 'assert'
|
||||||
|
|
||||||
|
export default function (state) {
|
||||||
|
const { selection } = state
|
||||||
|
|
||||||
|
const next = state
|
||||||
|
.change()
|
||||||
|
.removeMarkByKey('a', 0, 4, 'bold')
|
||||||
|
.state
|
||||||
|
|
||||||
|
.change()
|
||||||
|
.undo()
|
||||||
|
.state
|
||||||
|
|
||||||
|
assert.deepEqual(next.selection.toJS(), selection.toJS())
|
||||||
|
return next
|
||||||
|
}
|
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: paragraph
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
key: a
|
||||||
|
text: text
|
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: paragraph
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
key: a
|
||||||
|
text: text
|
@@ -6,7 +6,7 @@ export default function (state) {
|
|||||||
|
|
||||||
const next = state
|
const next = state
|
||||||
.change()
|
.change()
|
||||||
.addMarkByKey('key1', 0, 8, 'marktype')
|
.addMarkByKey('a', 0, 8, 'marktype')
|
||||||
.state
|
.state
|
||||||
|
|
||||||
.change()
|
.change()
|
||||||
|
@@ -4,5 +4,10 @@ nodes:
|
|||||||
type: paragraph
|
type: paragraph
|
||||||
nodes:
|
nodes:
|
||||||
- kind: text
|
- kind: text
|
||||||
key: 'key1'
|
key: a
|
||||||
text: The text
|
ranges:
|
||||||
|
- text: te
|
||||||
|
marks: []
|
||||||
|
- text: xt
|
||||||
|
marks:
|
||||||
|
- type: bold
|
||||||
|
@@ -4,5 +4,9 @@ nodes:
|
|||||||
type: paragraph
|
type: paragraph
|
||||||
nodes:
|
nodes:
|
||||||
- kind: text
|
- kind: text
|
||||||
key: 'key1'
|
key: a
|
||||||
text: The text
|
ranges:
|
||||||
|
- text: te
|
||||||
|
- text: xt
|
||||||
|
marks:
|
||||||
|
- type: bold
|
||||||
|
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
import assert from 'assert'
|
||||||
|
|
||||||
|
export default function (state) {
|
||||||
|
const { selection } = state
|
||||||
|
|
||||||
|
const next = state
|
||||||
|
.change()
|
||||||
|
.addMarkByKey('a', 0, 4, 'bold')
|
||||||
|
.state
|
||||||
|
|
||||||
|
.change()
|
||||||
|
.undo()
|
||||||
|
.state
|
||||||
|
|
||||||
|
assert.deepEqual(next.selection.toJS(), selection.toJS())
|
||||||
|
return next
|
||||||
|
}
|
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: paragraph
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
key: a
|
||||||
|
text: text
|
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
nodes:
|
||||||
|
- kind: block
|
||||||
|
type: paragraph
|
||||||
|
nodes:
|
||||||
|
- kind: text
|
||||||
|
key: a
|
||||||
|
text: text
|
Reference in New Issue
Block a user