prosemirror-transform 1.4.0 → 1.5.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.cjs +1781 -0
- package/dist/index.d.ts +690 -0
- package/dist/index.es.js +31 -33
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +1699 -1638
- package/dist/index.js.map +1 -1
- package/package.json +14 -12
- package/src/{index.js → index.ts} +4 -2
- package/src/map.ts +256 -0
- package/src/{mark.js → mark.ts} +22 -35
- package/src/{mark_step.js → mark_step.ts} +40 -39
- package/src/{replace.js → replace.ts} +92 -142
- package/src/{replace_step.js → replace_step.ts} +65 -70
- package/src/step.ts +97 -0
- package/src/{structure.js → structure.ts} +78 -99
- package/src/transform.ts +212 -0
- package/rollup.config.js +0 -14
- package/src/map.js +0 -264
- package/src/step.js +0 -110
- package/src/transform.js +0 -71
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {Fragment, Slice} from "prosemirror-model"
|
|
1
|
+
import {Fragment, Slice, Node, ResolvedPos, NodeType, ContentMatch, Attrs} from "prosemirror-model"
|
|
2
2
|
|
|
3
|
+
import {Step} from "./step"
|
|
3
4
|
import {ReplaceStep, ReplaceAroundStep} from "./replace_step"
|
|
4
5
|
import {Transform} from "./transform"
|
|
5
6
|
import {insertPoint} from "./structure"
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export function replaceStep(doc, from, to = from, slice = Slice.empty) {
|
|
8
|
+
/// ‘Fit’ a slice into a given position in the document, producing a
|
|
9
|
+
/// [step](#transform.Step) that inserts it. Will return null if
|
|
10
|
+
/// there's no meaningful way to insert the slice here, or inserting it
|
|
11
|
+
/// would be a no-op (an empty slice over an empty range).
|
|
12
|
+
export function replaceStep(doc: Node, from: number, to = from, slice = Slice.empty): Step | null {
|
|
13
13
|
if (from == to && !slice.size) return null
|
|
14
14
|
|
|
15
15
|
let $from = doc.resolve(from), $to = doc.resolve(to)
|
|
@@ -18,39 +18,19 @@ export function replaceStep(doc, from, to = from, slice = Slice.empty) {
|
|
|
18
18
|
return new Fitter($from, $to, slice).fit()
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
// Replace the part of the document between `from` and `to` with the
|
|
23
|
-
// given `slice`.
|
|
24
|
-
Transform.prototype.replace = function(from, to = from, slice = Slice.empty) {
|
|
25
|
-
let step = replaceStep(this.doc, from, to, slice)
|
|
26
|
-
if (step) this.step(step)
|
|
27
|
-
return this
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// :: (number, number, union<Fragment, Node, [Node]>) → this
|
|
31
|
-
// Replace the given range with the given content, which may be a
|
|
32
|
-
// fragment, node, or array of nodes.
|
|
33
|
-
Transform.prototype.replaceWith = function(from, to, content) {
|
|
34
|
-
return this.replace(from, to, new Slice(Fragment.from(content), 0, 0))
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// :: (number, number) → this
|
|
38
|
-
// Delete the content between the given positions.
|
|
39
|
-
Transform.prototype.delete = function(from, to) {
|
|
40
|
-
return this.replace(from, to, Slice.empty)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// :: (number, union<Fragment, Node, [Node]>) → this
|
|
44
|
-
// Insert the given content at the given position.
|
|
45
|
-
Transform.prototype.insert = function(pos, content) {
|
|
46
|
-
return this.replaceWith(pos, pos, content)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function fitsTrivially($from, $to, slice) {
|
|
21
|
+
function fitsTrivially($from: ResolvedPos, $to: ResolvedPos, slice: Slice) {
|
|
50
22
|
return !slice.openStart && !slice.openEnd && $from.start() == $to.start() &&
|
|
51
23
|
$from.parent.canReplace($from.index(), $to.index(), slice.content)
|
|
52
24
|
}
|
|
53
25
|
|
|
26
|
+
interface Fittable {
|
|
27
|
+
sliceDepth: number
|
|
28
|
+
frontierDepth: number
|
|
29
|
+
parent: Node | null
|
|
30
|
+
inject?: Fragment | null
|
|
31
|
+
wrap?: readonly NodeType[]
|
|
32
|
+
}
|
|
33
|
+
|
|
54
34
|
// Algorithm for 'placing' the elements of a slice into a gap:
|
|
55
35
|
//
|
|
56
36
|
// We consider the content of each node that is open to the left to be
|
|
@@ -72,12 +52,14 @@ function fitsTrivially($from, $to, slice) {
|
|
|
72
52
|
// - `placed` is a fragment of placed content. Its open-start value
|
|
73
53
|
// is implicit in `$from`, and its open-end value in `frontier`.
|
|
74
54
|
class Fitter {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
55
|
+
frontier: {type: NodeType, match: ContentMatch}[] = []
|
|
56
|
+
placed: Fragment = Fragment.empty
|
|
57
|
+
|
|
58
|
+
constructor(
|
|
59
|
+
readonly $from: ResolvedPos,
|
|
60
|
+
readonly $to: ResolvedPos,
|
|
61
|
+
public unplaced: Slice
|
|
62
|
+
) {
|
|
81
63
|
for (let i = 0; i <= $from.depth; i++) {
|
|
82
64
|
let node = $from.node(i)
|
|
83
65
|
this.frontier.push({
|
|
@@ -86,7 +68,6 @@ class Fitter {
|
|
|
86
68
|
})
|
|
87
69
|
}
|
|
88
70
|
|
|
89
|
-
this.placed = Fragment.empty
|
|
90
71
|
for (let i = $from.depth; i > 0; i--)
|
|
91
72
|
this.placed = Fragment.from($from.node(i).copy(this.placed))
|
|
92
73
|
}
|
|
@@ -114,7 +95,7 @@ class Fitter {
|
|
|
114
95
|
// If closing to `$to` succeeded, create a step
|
|
115
96
|
let content = this.placed, openStart = $from.depth, openEnd = $to.depth
|
|
116
97
|
while (openStart && openEnd && content.childCount == 1) { // Normalize by dropping open parent nodes
|
|
117
|
-
content = content.firstChild
|
|
98
|
+
content = content.firstChild!.content
|
|
118
99
|
openStart--; openEnd--
|
|
119
100
|
}
|
|
120
101
|
let slice = new Slice(content, openStart, openEnd)
|
|
@@ -122,31 +103,32 @@ class Fitter {
|
|
|
122
103
|
return new ReplaceAroundStep($from.pos, moveInline, this.$to.pos, this.$to.end(), slice, placedSize)
|
|
123
104
|
if (slice.size || $from.pos != this.$to.pos) // Don't generate no-op steps
|
|
124
105
|
return new ReplaceStep($from.pos, $to.pos, slice)
|
|
106
|
+
return null
|
|
125
107
|
}
|
|
126
108
|
|
|
127
109
|
// Find a position on the start spine of `this.unplaced` that has
|
|
128
110
|
// content that can be moved somewhere on the frontier. Returns two
|
|
129
111
|
// depths, one for the slice and one for the frontier.
|
|
130
|
-
findFittable() {
|
|
112
|
+
findFittable(): Fittable | undefined {
|
|
131
113
|
// Only try wrapping nodes (pass 2) after finding a place without
|
|
132
114
|
// wrapping failed.
|
|
133
115
|
for (let pass = 1; pass <= 2; pass++) {
|
|
134
116
|
for (let sliceDepth = this.unplaced.openStart; sliceDepth >= 0; sliceDepth--) {
|
|
135
|
-
let fragment, parent
|
|
117
|
+
let fragment, parent = null
|
|
136
118
|
if (sliceDepth) {
|
|
137
119
|
parent = contentAt(this.unplaced.content, sliceDepth - 1).firstChild
|
|
138
|
-
fragment = parent
|
|
120
|
+
fragment = parent!.content
|
|
139
121
|
} else {
|
|
140
122
|
fragment = this.unplaced.content
|
|
141
123
|
}
|
|
142
124
|
let first = fragment.firstChild
|
|
143
125
|
for (let frontierDepth = this.depth; frontierDepth >= 0; frontierDepth--) {
|
|
144
|
-
let {type, match} = this.frontier[frontierDepth], wrap, inject
|
|
126
|
+
let {type, match} = this.frontier[frontierDepth], wrap, inject: Fragment | null = null
|
|
145
127
|
// In pass 1, if the next node matches, or there is no next
|
|
146
128
|
// node but the parents look compatible, we've found a
|
|
147
129
|
// place.
|
|
148
130
|
if (pass == 1 && (first ? match.matchType(first.type) || (inject = match.fillBefore(Fragment.from(first), false))
|
|
149
|
-
: type.compatibleContent(parent.type)))
|
|
131
|
+
: parent && type.compatibleContent(parent.type)))
|
|
150
132
|
return {sliceDepth, frontierDepth, parent, inject}
|
|
151
133
|
// In pass 2, look for a set of wrapping nodes that make
|
|
152
134
|
// `first` fit here.
|
|
@@ -163,7 +145,7 @@ class Fitter {
|
|
|
163
145
|
openMore() {
|
|
164
146
|
let {content, openStart, openEnd} = this.unplaced
|
|
165
147
|
let inner = contentAt(content, openStart)
|
|
166
|
-
if (!inner.childCount || inner.firstChild
|
|
148
|
+
if (!inner.childCount || inner.firstChild!.isLeaf) return false
|
|
167
149
|
this.unplaced = new Slice(content, openStart + 1,
|
|
168
150
|
Math.max(openEnd, inner.size + openStart >= content.size - openEnd ? openStart + 1 : 0))
|
|
169
151
|
return true
|
|
@@ -181,11 +163,10 @@ class Fitter {
|
|
|
181
163
|
}
|
|
182
164
|
}
|
|
183
165
|
|
|
184
|
-
// : ({sliceDepth: number, frontierDepth: number, parent: ?Node, wrap: ?[NodeType], inject: ?Fragment})
|
|
185
166
|
// Move content from the unplaced slice at `sliceDepth` to the
|
|
186
167
|
// frontier node at `frontierDepth`. Close that frontier node when
|
|
187
168
|
// applicable.
|
|
188
|
-
placeNodes({sliceDepth, frontierDepth, parent, inject, wrap}) {
|
|
169
|
+
placeNodes({sliceDepth, frontierDepth, parent, inject, wrap}: Fittable) {
|
|
189
170
|
while (this.depth > frontierDepth) this.closeFrontierNode()
|
|
190
171
|
if (wrap) for (let i = 0; i < wrap.length; i++) this.openFrontierNode(wrap[i])
|
|
191
172
|
|
|
@@ -195,7 +176,7 @@ class Fitter {
|
|
|
195
176
|
let {match, type} = this.frontier[frontierDepth]
|
|
196
177
|
if (inject) {
|
|
197
178
|
for (let i = 0; i < inject.childCount; i++) add.push(inject.child(i))
|
|
198
|
-
match = match.matchFragment(inject)
|
|
179
|
+
match = match.matchFragment(inject)!
|
|
199
180
|
}
|
|
200
181
|
// Computes the amount of (end) open nodes at the end of the
|
|
201
182
|
// fragment. When 0, the parent is open, but no more. When
|
|
@@ -226,7 +207,7 @@ class Fitter {
|
|
|
226
207
|
|
|
227
208
|
// Add new frontier nodes for any open nodes at the end.
|
|
228
209
|
for (let i = 0, cur = fragment; i < openEndCount; i++) {
|
|
229
|
-
let node = cur.lastChild
|
|
210
|
+
let node = cur.lastChild!
|
|
230
211
|
this.frontier.push({type: node.type, match: node.contentMatchAt(node.childCount)})
|
|
231
212
|
cur = node.content
|
|
232
213
|
}
|
|
@@ -241,7 +222,7 @@ class Fitter {
|
|
|
241
222
|
}
|
|
242
223
|
|
|
243
224
|
mustMoveInline() {
|
|
244
|
-
if (!this.$to.parent.isTextblock
|
|
225
|
+
if (!this.$to.parent.isTextblock) return -1
|
|
245
226
|
let top = this.frontier[this.depth], level
|
|
246
227
|
if (!top.type.isTextblock || !contentAfterFits(this.$to, this.$to.depth, top.type, top.match, false) ||
|
|
247
228
|
(this.$to.depth == this.depth && (level = this.findCloseLevel(this.$to)) && level.depth == this.depth)) return -1
|
|
@@ -251,7 +232,7 @@ class Fitter {
|
|
|
251
232
|
return after
|
|
252
233
|
}
|
|
253
234
|
|
|
254
|
-
findCloseLevel($to) {
|
|
235
|
+
findCloseLevel($to: ResolvedPos) {
|
|
255
236
|
scan: for (let i = Math.min(this.depth, $to.depth); i >= 0; i--) {
|
|
256
237
|
let {match, type} = this.frontier[i]
|
|
257
238
|
let dropInner = i < $to.depth && $to.end(i + 1) == $to.pos + ($to.depth - (i + 1))
|
|
@@ -266,7 +247,7 @@ class Fitter {
|
|
|
266
247
|
}
|
|
267
248
|
}
|
|
268
249
|
|
|
269
|
-
close($to) {
|
|
250
|
+
close($to: ResolvedPos) {
|
|
270
251
|
let close = this.findCloseLevel($to)
|
|
271
252
|
if (!close) return null
|
|
272
253
|
|
|
@@ -274,95 +255,79 @@ class Fitter {
|
|
|
274
255
|
if (close.fit.childCount) this.placed = addToFragment(this.placed, close.depth, close.fit)
|
|
275
256
|
$to = close.move
|
|
276
257
|
for (let d = close.depth + 1; d <= $to.depth; d++) {
|
|
277
|
-
let node = $to.node(d), add = node.type.contentMatch.fillBefore(node.content, true, $to.index(d))
|
|
258
|
+
let node = $to.node(d), add = node.type.contentMatch.fillBefore(node.content, true, $to.index(d))!
|
|
278
259
|
this.openFrontierNode(node.type, node.attrs, add)
|
|
279
260
|
}
|
|
280
261
|
return $to
|
|
281
262
|
}
|
|
282
263
|
|
|
283
|
-
openFrontierNode(type, attrs, content) {
|
|
264
|
+
openFrontierNode(type: NodeType, attrs: Attrs | null = null, content?: Fragment) {
|
|
284
265
|
let top = this.frontier[this.depth]
|
|
285
|
-
top.match = top.match.matchType(type)
|
|
266
|
+
top.match = top.match.matchType(type)!
|
|
286
267
|
this.placed = addToFragment(this.placed, this.depth, Fragment.from(type.create(attrs, content)))
|
|
287
268
|
this.frontier.push({type, match: type.contentMatch})
|
|
288
269
|
}
|
|
289
270
|
|
|
290
271
|
closeFrontierNode() {
|
|
291
|
-
let open = this.frontier.pop()
|
|
292
|
-
let add = open.match.fillBefore(Fragment.empty, true)
|
|
272
|
+
let open = this.frontier.pop()!
|
|
273
|
+
let add = open.match.fillBefore(Fragment.empty, true)!
|
|
293
274
|
if (add.childCount) this.placed = addToFragment(this.placed, this.frontier.length, add)
|
|
294
275
|
}
|
|
295
276
|
}
|
|
296
277
|
|
|
297
|
-
function dropFromFragment(fragment, depth, count) {
|
|
298
|
-
if (depth == 0) return fragment.cutByIndex(count)
|
|
299
|
-
return fragment.replaceChild(0, fragment.firstChild
|
|
278
|
+
function dropFromFragment(fragment: Fragment, depth: number, count: number): Fragment {
|
|
279
|
+
if (depth == 0) return fragment.cutByIndex(count, fragment.childCount)
|
|
280
|
+
return fragment.replaceChild(0, fragment.firstChild!.copy(dropFromFragment(fragment.firstChild!.content, depth - 1, count)))
|
|
300
281
|
}
|
|
301
282
|
|
|
302
|
-
function addToFragment(fragment, depth, content) {
|
|
283
|
+
function addToFragment(fragment: Fragment, depth: number, content: Fragment): Fragment {
|
|
303
284
|
if (depth == 0) return fragment.append(content)
|
|
304
285
|
return fragment.replaceChild(fragment.childCount - 1,
|
|
305
|
-
fragment.lastChild
|
|
286
|
+
fragment.lastChild!.copy(addToFragment(fragment.lastChild!.content, depth - 1, content)))
|
|
306
287
|
}
|
|
307
288
|
|
|
308
|
-
function contentAt(fragment, depth) {
|
|
309
|
-
for (let i = 0; i < depth; i++) fragment = fragment.firstChild
|
|
289
|
+
function contentAt(fragment: Fragment, depth: number) {
|
|
290
|
+
for (let i = 0; i < depth; i++) fragment = fragment.firstChild!.content
|
|
310
291
|
return fragment
|
|
311
292
|
}
|
|
312
293
|
|
|
313
|
-
function closeNodeStart(node, openStart, openEnd) {
|
|
294
|
+
function closeNodeStart(node: Node, openStart: number, openEnd: number) {
|
|
314
295
|
if (openStart <= 0) return node
|
|
315
296
|
let frag = node.content
|
|
316
297
|
if (openStart > 1)
|
|
317
|
-
frag = frag.replaceChild(0, closeNodeStart(frag.firstChild
|
|
298
|
+
frag = frag.replaceChild(0, closeNodeStart(frag.firstChild!, openStart - 1, frag.childCount == 1 ? openEnd - 1 : 0))
|
|
318
299
|
if (openStart > 0) {
|
|
319
|
-
frag = node.type.contentMatch.fillBefore(frag)
|
|
320
|
-
if (openEnd <= 0) frag = frag.append(node.type.contentMatch.matchFragment(frag)
|
|
300
|
+
frag = node.type.contentMatch.fillBefore(frag)!.append(frag)
|
|
301
|
+
if (openEnd <= 0) frag = frag.append(node.type.contentMatch.matchFragment(frag)!.fillBefore(Fragment.empty, true)!)
|
|
321
302
|
}
|
|
322
303
|
return node.copy(frag)
|
|
323
304
|
}
|
|
324
305
|
|
|
325
|
-
function contentAfterFits($to, depth, type, match, open) {
|
|
306
|
+
function contentAfterFits($to: ResolvedPos, depth: number, type: NodeType, match: ContentMatch, open: boolean) {
|
|
326
307
|
let node = $to.node(depth), index = open ? $to.indexAfter(depth) : $to.index(depth)
|
|
327
308
|
if (index == node.childCount && !type.compatibleContent(node.type)) return null
|
|
328
309
|
let fit = match.fillBefore(node.content, true, index)
|
|
329
310
|
return fit && !invalidMarks(type, node.content, index) ? fit : null
|
|
330
311
|
}
|
|
331
312
|
|
|
332
|
-
function invalidMarks(type, fragment, start) {
|
|
313
|
+
function invalidMarks(type: NodeType, fragment: Fragment, start: number) {
|
|
333
314
|
for (let i = start; i < fragment.childCount; i++)
|
|
334
315
|
if (!type.allowsMarks(fragment.child(i).marks)) return true
|
|
335
316
|
return false
|
|
336
317
|
}
|
|
337
318
|
|
|
338
|
-
function definesContent(type) {
|
|
319
|
+
function definesContent(type: NodeType) {
|
|
339
320
|
return type.spec.defining || type.spec.definingForContent
|
|
340
321
|
}
|
|
341
322
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
// grow the replaced area or close open nodes in the slice in order to
|
|
347
|
-
// get a fit that is more in line with WYSIWYG expectations, by
|
|
348
|
-
// dropping fully covered parent nodes of the replaced region when
|
|
349
|
-
// they are marked [non-defining as context](#model.NodeSpec.definingAsContext), or
|
|
350
|
-
// including an open parent node from the slice that _is_ marked as
|
|
351
|
-
// [defining its content](#model.NodeSpec.definingForContent).
|
|
352
|
-
//
|
|
353
|
-
// This is the method, for example, to handle paste. The similar
|
|
354
|
-
// [`replace`](#transform.Transform.replace) method is a more
|
|
355
|
-
// primitive tool which will _not_ move the start and end of its given
|
|
356
|
-
// range, and is useful in situations where you need more precise
|
|
357
|
-
// control over what happens.
|
|
358
|
-
Transform.prototype.replaceRange = function(from, to, slice) {
|
|
359
|
-
if (!slice.size) return this.deleteRange(from, to)
|
|
360
|
-
|
|
361
|
-
let $from = this.doc.resolve(from), $to = this.doc.resolve(to)
|
|
323
|
+
export function replaceRange(tr: Transform, from: number, to: number, slice: Slice) {
|
|
324
|
+
if (!slice.size) return tr.deleteRange(from, to)
|
|
325
|
+
|
|
326
|
+
let $from = tr.doc.resolve(from), $to = tr.doc.resolve(to)
|
|
362
327
|
if (fitsTrivially($from, $to, slice))
|
|
363
|
-
return
|
|
328
|
+
return tr.step(new ReplaceStep(from, to, slice))
|
|
364
329
|
|
|
365
|
-
let targetDepths = coveredDepths($from,
|
|
330
|
+
let targetDepths = coveredDepths($from, tr.doc.resolve(to))
|
|
366
331
|
// Can't replace the whole document, so remove 0 if it's present
|
|
367
332
|
if (targetDepths[targetDepths.length - 1] == 0) targetDepths.pop()
|
|
368
333
|
// Negative numbers represent not expansion over the whole node at
|
|
@@ -385,21 +350,19 @@ Transform.prototype.replaceRange = function(from, to, slice) {
|
|
|
385
350
|
|
|
386
351
|
let leftNodes = [], preferredDepth = slice.openStart
|
|
387
352
|
for (let content = slice.content, i = 0;; i++) {
|
|
388
|
-
let node = content.firstChild
|
|
353
|
+
let node = content.firstChild!
|
|
389
354
|
leftNodes.push(node)
|
|
390
355
|
if (i == slice.openStart) break
|
|
391
356
|
content = node.content
|
|
392
357
|
}
|
|
393
|
-
|
|
394
|
-
//
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
$from.node(preferredTargetIndex).type != leftNodes[preferredDepth - 2].type)
|
|
402
|
-
preferredDepth -= 2
|
|
358
|
+
|
|
359
|
+
// Back up preferredDepth to cover defining textblocks directly
|
|
360
|
+
// above it, possibly skipping a non-defining textblock.
|
|
361
|
+
for (let d = preferredDepth - 1; d >= 0; d--) {
|
|
362
|
+
let type = leftNodes[d].type, def = definesContent(type)
|
|
363
|
+
if (def && $from.node(preferredTargetIndex).type != type) preferredDepth = d
|
|
364
|
+
else if (def || !type.isTextblock) break
|
|
365
|
+
}
|
|
403
366
|
|
|
404
367
|
for (let j = slice.openStart; j >= 0; j--) {
|
|
405
368
|
let openDepth = (j + preferredDepth + 1) % (slice.openStart + 1)
|
|
@@ -412,76 +375,63 @@ Transform.prototype.replaceRange = function(from, to, slice) {
|
|
|
412
375
|
if (targetDepth < 0) { expand = false; targetDepth = -targetDepth }
|
|
413
376
|
let parent = $from.node(targetDepth - 1), index = $from.index(targetDepth - 1)
|
|
414
377
|
if (parent.canReplaceWith(index, index, insert.type, insert.marks))
|
|
415
|
-
return
|
|
378
|
+
return tr.replace($from.before(targetDepth), expand ? $to.after(targetDepth) : to,
|
|
416
379
|
new Slice(closeFragment(slice.content, 0, slice.openStart, openDepth),
|
|
417
380
|
openDepth, slice.openEnd))
|
|
418
381
|
}
|
|
419
382
|
}
|
|
420
383
|
|
|
421
|
-
let startSteps =
|
|
384
|
+
let startSteps = tr.steps.length
|
|
422
385
|
for (let i = targetDepths.length - 1; i >= 0; i--) {
|
|
423
|
-
|
|
424
|
-
if (
|
|
386
|
+
tr.replace(from, to, slice)
|
|
387
|
+
if (tr.steps.length > startSteps) break
|
|
425
388
|
let depth = targetDepths[i]
|
|
426
389
|
if (depth < 0) continue
|
|
427
390
|
from = $from.before(depth); to = $to.after(depth)
|
|
428
391
|
}
|
|
429
|
-
return this
|
|
430
392
|
}
|
|
431
393
|
|
|
432
|
-
function closeFragment(fragment, depth, oldOpen, newOpen, parent) {
|
|
394
|
+
function closeFragment(fragment: Fragment, depth: number, oldOpen: number, newOpen: number, parent?: Node) {
|
|
433
395
|
if (depth < oldOpen) {
|
|
434
|
-
let first = fragment.firstChild
|
|
396
|
+
let first = fragment.firstChild!
|
|
435
397
|
fragment = fragment.replaceChild(0, first.copy(closeFragment(first.content, depth + 1, oldOpen, newOpen, first)))
|
|
436
398
|
}
|
|
437
399
|
if (depth > newOpen) {
|
|
438
|
-
let match = parent
|
|
439
|
-
let start = match.fillBefore(fragment)
|
|
440
|
-
fragment = start.append(match.matchFragment(start)
|
|
400
|
+
let match = parent!.contentMatchAt(0)!
|
|
401
|
+
let start = match.fillBefore(fragment)!.append(fragment)
|
|
402
|
+
fragment = start.append(match.matchFragment(start)!.fillBefore(Fragment.empty, true)!)
|
|
441
403
|
}
|
|
442
404
|
return fragment
|
|
443
405
|
}
|
|
444
406
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
// and are at the start or end of a parent node in which the given
|
|
449
|
-
// node doesn't fit, this method may _move_ them out towards a parent
|
|
450
|
-
// that does allow the given node to be placed. When the given range
|
|
451
|
-
// completely covers a parent node, this method may completely replace
|
|
452
|
-
// that parent node.
|
|
453
|
-
Transform.prototype.replaceRangeWith = function(from, to, node) {
|
|
454
|
-
if (!node.isInline && from == to && this.doc.resolve(from).parent.content.size) {
|
|
455
|
-
let point = insertPoint(this.doc, from, node.type)
|
|
407
|
+
export function replaceRangeWith(tr: Transform, from: number, to: number, node: Node) {
|
|
408
|
+
if (!node.isInline && from == to && tr.doc.resolve(from).parent.content.size) {
|
|
409
|
+
let point = insertPoint(tr.doc, from, node.type)
|
|
456
410
|
if (point != null) from = to = point
|
|
457
411
|
}
|
|
458
|
-
|
|
412
|
+
tr.replaceRange(from, to, new Slice(Fragment.from(node), 0, 0))
|
|
459
413
|
}
|
|
460
414
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
// parent nodes until a valid replace is found.
|
|
464
|
-
Transform.prototype.deleteRange = function(from, to) {
|
|
465
|
-
let $from = this.doc.resolve(from), $to = this.doc.resolve(to)
|
|
415
|
+
export function deleteRange(tr: Transform, from: number, to: number) {
|
|
416
|
+
let $from = tr.doc.resolve(from), $to = tr.doc.resolve(to)
|
|
466
417
|
let covered = coveredDepths($from, $to)
|
|
467
418
|
for (let i = 0; i < covered.length; i++) {
|
|
468
419
|
let depth = covered[i], last = i == covered.length - 1
|
|
469
420
|
if ((last && depth == 0) || $from.node(depth).type.contentMatch.validEnd)
|
|
470
|
-
return
|
|
421
|
+
return tr.delete($from.start(depth), $to.end(depth))
|
|
471
422
|
if (depth > 0 && (last || $from.node(depth - 1).canReplace($from.index(depth - 1), $to.indexAfter(depth - 1))))
|
|
472
|
-
return
|
|
423
|
+
return tr.delete($from.before(depth), $to.after(depth))
|
|
473
424
|
}
|
|
474
425
|
for (let d = 1; d <= $from.depth && d <= $to.depth; d++) {
|
|
475
426
|
if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d)
|
|
476
|
-
return
|
|
427
|
+
return tr.delete($from.before(d), to)
|
|
477
428
|
}
|
|
478
|
-
|
|
429
|
+
tr.delete(from, to)
|
|
479
430
|
}
|
|
480
431
|
|
|
481
|
-
// : (ResolvedPos, ResolvedPos) → [number]
|
|
482
432
|
// Returns an array of all depths for which $from - $to spans the
|
|
483
433
|
// whole content of the nodes at that depth.
|
|
484
|
-
function coveredDepths($from, $to) {
|
|
434
|
+
function coveredDepths($from: ResolvedPos, $to: ResolvedPos) {
|
|
485
435
|
let result = [], minDepth = Math.min($from.depth, $to.depth)
|
|
486
436
|
for (let d = minDepth; d >= 0; d--) {
|
|
487
437
|
let start = $from.start(d)
|