/
wrapInList.js
103 lines (96 loc) · 2.51 KB
/
wrapInList.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// @flow
// https://github.com/ProseMirror/prosemirror-schema-list/blob/master/src/schema-list.js
import {Fragment, Schema, NodeType, NodeRange, ResolvedPos, Slice} from 'prosemirror-model';
import {canSplit, findWrapping, ReplaceAroundStep} from 'prosemirror-transform';
import {Transform} from 'prosemirror-transform';
export default function wrapInList(
tr: Transform,
nodeType: NodeType,
attrs?: ?Object,
): Transform {
const {selection, doc} = tr;
if (!selection || !doc) {
return tr;
}
let {$from, $to} = selection;
let range = $from.blockRange($to);
let doJoin = false;
let outerRange = range;
if (!range) {
return tr;
}
// This is at the top of an existing list item
if (
range.depth >= 2 &&
$from.node(range.depth - 1).type.compatibleContent(nodeType) &&
range.startIndex === 0
) {
// Don't do anything if this is the top of the list
if ($from.index(range.depth - 1) == 0) {
return tr;
}
let $insert = tr.doc.resolve(range.start - 2);
outerRange = new NodeRange($insert, $insert, range.depth);
if (range.endIndex < range.parent.childCount) {
range = new NodeRange(
$from,
tr.doc.resolve($to.end(range.depth)),
range.depth,
);
}
doJoin = true;
}
const wrappers = findWrapping(outerRange, nodeType, attrs, range);
return doWrapInList(
tr,
range,
wrappers,
doJoin,
nodeType,
);
}
function doWrapInList(
tr: Transform,
range: NodeRange,
wrappers: any,
doJoin: boolean,
nodeType: NodeType,
): Transform {
if (!wrappers) {
return tr;
}
let content = Fragment.empty;
for (let i = wrappers.length - 1; i >= 0; i--) {
content = Fragment.from(
wrappers[i].type.create(wrappers[i].attrs, content),
);
}
tr = tr.step(
new ReplaceAroundStep(range.start - (doJoin ? 2 : 0),
range.end,
range.start,
range.end,
new Slice(content, 0, 0), wrappers.length, true),
);
let found = 0
for (let i = 0; i < wrappers.length; i++) {
if (wrappers[i].type == nodeType) {
found = i + 1;
}
};
let splitDepth = wrappers.length - found;
let splitPos = range.start + wrappers.length - (doJoin ? 2 : 0);
let parent = range.parent;
for (
let i = range.startIndex, e = range.endIndex, first = true;
i < e; i++,
first = false
) {
if (!first && canSplit(tr.doc, splitPos, splitDepth)) {
tr = tr.split(splitPos, splitDepth)
splitPos += 2 * splitDepth;
}
splitPos += parent.child(i).nodeSize;
}
return tr;
}