@milkdown/preset-gfm 6.5.2 → 6.5.4
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/lib/footnote/definition.d.ts +1 -1
- package/lib/footnote/definition.d.ts.map +1 -1
- package/lib/footnote/index.d.ts.map +1 -1
- package/lib/footnote/reference.d.ts +1 -1
- package/lib/footnote/reference.d.ts.map +1 -1
- package/lib/footnote/utils.d.ts.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +649 -607
- package/lib/index.es.js.map +1 -1
- package/lib/strike-through.d.ts +1 -1
- package/lib/strike-through.d.ts.map +1 -1
- package/lib/supported-keys.d.ts +1 -1
- package/lib/supported-keys.d.ts.map +1 -1
- package/lib/table/command.d.ts +2 -2
- package/lib/table/command.d.ts.map +1 -1
- package/lib/table/index.d.ts +1 -1
- package/lib/table/index.d.ts.map +1 -1
- package/lib/table/nodes/index.d.ts +1 -1
- package/lib/table/nodes/index.d.ts.map +1 -1
- package/lib/table/operator-plugin/actions.d.ts +5 -5
- package/lib/table/operator-plugin/actions.d.ts.map +1 -1
- package/lib/table/operator-plugin/calc-pos.d.ts +1 -1
- package/lib/table/operator-plugin/calc-pos.d.ts.map +1 -1
- package/lib/table/operator-plugin/constant.d.ts.map +1 -1
- package/lib/table/operator-plugin/helper.d.ts +3 -3
- package/lib/table/operator-plugin/helper.d.ts.map +1 -1
- package/lib/table/operator-plugin/index.d.ts +2 -2
- package/lib/table/operator-plugin/index.d.ts.map +1 -1
- package/lib/table/operator-plugin/style.d.ts +1 -1
- package/lib/table/operator-plugin/style.d.ts.map +1 -1
- package/lib/table/operator-plugin/widget.d.ts +2 -2
- package/lib/table/operator-plugin/widget.d.ts.map +1 -1
- package/lib/table/plugin/auto-insert-zero-space.d.ts.map +1 -1
- package/lib/table/plugin/cell-selection.d.ts +5 -3
- package/lib/table/plugin/cell-selection.d.ts.map +1 -1
- package/lib/table/plugin/column-resizing.d.ts +2 -1
- package/lib/table/plugin/column-resizing.d.ts.map +1 -1
- package/lib/table/plugin/commands.d.ts +2 -2
- package/lib/table/plugin/commands.d.ts.map +1 -1
- package/lib/table/plugin/copy-paste.d.ts +6 -5
- package/lib/table/plugin/copy-paste.d.ts.map +1 -1
- package/lib/table/plugin/fix-tables.d.ts +3 -2
- package/lib/table/plugin/fix-tables.d.ts.map +1 -1
- package/lib/table/plugin/index.d.ts.map +1 -1
- package/lib/table/plugin/schema.d.ts +1 -1
- package/lib/table/plugin/schema.d.ts.map +1 -1
- package/lib/table/plugin/table-editing.d.ts +1 -1
- package/lib/table/plugin/table-editing.d.ts.map +1 -1
- package/lib/table/plugin/table-map.d.ts +2 -2
- package/lib/table/plugin/table-map.d.ts.map +1 -1
- package/lib/table/plugin/table-view.d.ts +2 -2
- package/lib/table/plugin/table-view.d.ts.map +1 -1
- package/lib/table/plugin/types.d.ts +2 -2
- package/lib/table/plugin/types.d.ts.map +1 -1
- package/lib/table/plugin/util.d.ts +2 -2
- package/lib/table/plugin/util.d.ts.map +1 -1
- package/lib/table/utils.d.ts +5 -5
- package/lib/table/utils.d.ts.map +1 -1
- package/lib/task-list-item.d.ts +2 -2
- package/lib/task-list-item.d.ts.map +1 -1
- package/package.json +22 -17
- package/src/footnote/definition.ts +172 -166
- package/src/footnote/index.ts +2 -2
- package/src/footnote/reference.ts +166 -162
- package/src/footnote/utils.ts +2 -2
- package/src/index.ts +83 -83
- package/src/strike-through.ts +36 -36
- package/src/supported-keys.ts +9 -8
- package/src/table/command.ts +17 -16
- package/src/table/index.ts +9 -9
- package/src/table/nodes/index.ts +177 -174
- package/src/table/operator-plugin/actions.ts +103 -102
- package/src/table/operator-plugin/calc-pos.ts +31 -34
- package/src/table/operator-plugin/constant.ts +3 -3
- package/src/table/operator-plugin/helper.ts +31 -32
- package/src/table/operator-plugin/index.ts +104 -95
- package/src/table/operator-plugin/style.ts +10 -9
- package/src/table/operator-plugin/widget.ts +47 -45
- package/src/table/plugin/auto-insert-zero-space.ts +41 -41
- package/src/table/plugin/cell-selection.ts +325 -296
- package/src/table/plugin/column-resizing.ts +226 -198
- package/src/table/plugin/commands.ts +464 -421
- package/src/table/plugin/copy-paste.ts +256 -240
- package/src/table/plugin/fix-tables.ts +103 -88
- package/src/table/plugin/index.ts +3 -3
- package/src/table/plugin/schema.ts +100 -94
- package/src/table/plugin/table-editing.ts +324 -230
- package/src/table/plugin/table-map.ts +294 -229
- package/src/table/plugin/table-view.ts +66 -62
- package/src/table/plugin/types.ts +8 -8
- package/src/table/plugin/util.ts +78 -66
- package/src/table/utils.ts +141 -138
- package/src/task-list-item.ts +151 -146
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import type { Node, ResolvedPos } from '@milkdown/prose/model'
|
|
4
|
+
import { Fragment, Slice } from '@milkdown/prose/model'
|
|
5
|
+
import type {
|
|
6
|
+
EditorState,
|
|
7
|
+
Transaction,
|
|
8
|
+
} from '@milkdown/prose/state'
|
|
4
9
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from '@milkdown/prose/
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
import { TableMap } from './table-map';
|
|
16
|
-
import { inSameTable, pointsAtCell, removeColSpan, setAttr } from './util';
|
|
10
|
+
NodeSelection,
|
|
11
|
+
Selection,
|
|
12
|
+
SelectionRange,
|
|
13
|
+
TextSelection,
|
|
14
|
+
} from '@milkdown/prose/state'
|
|
15
|
+
import type { Mappable } from '@milkdown/prose/transform'
|
|
16
|
+
import { Decoration, DecorationSet } from '@milkdown/prose/view'
|
|
17
|
+
|
|
18
|
+
import { TableMap } from './table-map'
|
|
19
|
+
import { inSameTable, pointsAtCell, removeColSpan, setAttr } from './util'
|
|
17
20
|
|
|
18
21
|
// ::- A [`Selection`](http://prosemirror.net/docs/ref/#state.Selection)
|
|
19
22
|
// subclass that represents a cell selection spanning part of a table.
|
|
@@ -21,332 +24,358 @@ import { inSameTable, pointsAtCell, removeColSpan, setAttr } from './util';
|
|
|
21
24
|
// selects across cells, and will be drawn by giving selected cells a
|
|
22
25
|
// `selectedCell` CSS class.
|
|
23
26
|
export class CellSelection extends Selection {
|
|
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
|
-
|
|
27
|
+
// :: (ResolvedPos, ?ResolvedPos)
|
|
28
|
+
// A table selection is identified by its anchor and head cells. The
|
|
29
|
+
// positions given to this constructor should point _before_ two
|
|
30
|
+
// cells in the same table. They may be the same, to select a single
|
|
31
|
+
// cell.
|
|
32
|
+
constructor(public $anchorCell: ResolvedPos, public $headCell = $anchorCell) {
|
|
33
|
+
const table = $anchorCell.node(-1)
|
|
34
|
+
const map = TableMap.get(table)
|
|
35
|
+
const start = $anchorCell.start(-1)
|
|
36
|
+
const rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start)
|
|
37
|
+
const doc = $anchorCell.node(0)
|
|
38
|
+
const cells = map.cellsInRect(rect).filter(p => p != $headCell.pos - start)
|
|
39
|
+
// Make the head cell the first range, so that it counts as the
|
|
40
|
+
// primary part of the selection
|
|
41
|
+
cells.unshift($headCell.pos - start)
|
|
42
|
+
const ranges = cells.map((pos) => {
|
|
43
|
+
const cell = table.nodeAt(pos) as Node
|
|
44
|
+
const from = pos + start + 1
|
|
45
|
+
|
|
46
|
+
return new (SelectionRange as any)(doc.resolve(from), doc.resolve(from + cell.content.size))
|
|
47
|
+
})
|
|
48
|
+
super(ranges[0].$from, ranges[0].$to, ranges)
|
|
49
|
+
// :: ResolvedPos
|
|
50
|
+
// A resolved position pointing _in front of_ the anchor cell (the one
|
|
51
|
+
// that doesn't move when extending the selection).
|
|
52
|
+
this.$anchorCell = $anchorCell
|
|
53
|
+
// :: ResolvedPos
|
|
54
|
+
// A resolved position pointing in front of the head cell (the one
|
|
55
|
+
// moves when extending the selection).
|
|
56
|
+
this.$headCell = $headCell
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
map(doc: Node, mapping: Mappable): Selection {
|
|
60
|
+
const $anchorCell = doc.resolve(mapping.map(this.$anchorCell.pos))
|
|
61
|
+
const $headCell = doc.resolve(mapping.map(this.$headCell.pos))
|
|
62
|
+
if (pointsAtCell($anchorCell) && pointsAtCell($headCell) && inSameTable($anchorCell, $headCell)) {
|
|
63
|
+
const tableChanged = this.$anchorCell.node(-1) != $anchorCell.node(-1)
|
|
64
|
+
if (tableChanged && this.isRowSelection())
|
|
65
|
+
return CellSelection.rowSelection($anchorCell, $headCell)
|
|
66
|
+
else if (tableChanged && this.isColSelection())
|
|
67
|
+
return CellSelection.colSelection($anchorCell, $headCell)
|
|
68
|
+
else return new CellSelection($anchorCell, $headCell)
|
|
54
69
|
}
|
|
70
|
+
return TextSelection.between($anchorCell, $headCell)
|
|
71
|
+
}
|
|
55
72
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
// :: () → Slice
|
|
74
|
+
// Returns a rectangular slice of table rows containing the selected
|
|
75
|
+
// cells.
|
|
76
|
+
override content(): Slice {
|
|
77
|
+
const table = this.$anchorCell.node(-1)
|
|
78
|
+
const map = TableMap.get(table)
|
|
79
|
+
const start = this.$anchorCell.start(-1)
|
|
80
|
+
const rect = map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start)
|
|
81
|
+
const seen: Record<number, boolean> = {}
|
|
82
|
+
const rows = []
|
|
83
|
+
for (let row = rect.top; row < rect.bottom; row++) {
|
|
84
|
+
const rowContent = []
|
|
85
|
+
for (let index = row * map.width + rect.left, col = rect.left; col < rect.right; col++, index++) {
|
|
86
|
+
const pos = map.map[index] as number
|
|
87
|
+
if (!seen[pos]) {
|
|
88
|
+
seen[pos] = true
|
|
89
|
+
const cellRect = map.findCell(pos)
|
|
90
|
+
let cell = table.nodeAt(pos) as Node
|
|
91
|
+
const extraLeft = rect.left - cellRect.left
|
|
92
|
+
const extraRight = cellRect.right - rect.right
|
|
93
|
+
if (extraLeft > 0 || extraRight > 0) {
|
|
94
|
+
let attrs = cell.attrs
|
|
95
|
+
if (extraLeft > 0)
|
|
96
|
+
attrs = removeColSpan(attrs, 0, extraLeft)
|
|
97
|
+
if (extraRight > 0)
|
|
98
|
+
attrs = removeColSpan(attrs, attrs.colspan - extraRight, extraRight)
|
|
99
|
+
if (cellRect.left < rect.left)
|
|
100
|
+
cell = cell.type.createAndFill(attrs) as Node
|
|
101
|
+
else cell = cell.type.create(attrs, cell.content)
|
|
102
|
+
}
|
|
103
|
+
if (cellRect.top < rect.top || cellRect.bottom > rect.bottom) {
|
|
104
|
+
const attrs = setAttr(
|
|
105
|
+
cell.attrs,
|
|
106
|
+
'rowspan',
|
|
107
|
+
Math.min(cellRect.bottom, rect.bottom) - Math.max(cellRect.top, rect.top),
|
|
108
|
+
)
|
|
109
|
+
if (cellRect.top < rect.top)
|
|
110
|
+
cell = cell.type.createAndFill(attrs) as Node
|
|
111
|
+
else cell = cell.type.create(attrs, cell.content)
|
|
112
|
+
}
|
|
113
|
+
rowContent.push(cell)
|
|
64
114
|
}
|
|
65
|
-
|
|
115
|
+
}
|
|
116
|
+
rows.push(table.child(row).copy(Fragment.from(rowContent)))
|
|
66
117
|
}
|
|
67
118
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
override content(): Slice {
|
|
72
|
-
const table = this.$anchorCell.node(-1),
|
|
73
|
-
map = TableMap.get(table),
|
|
74
|
-
start = this.$anchorCell.start(-1);
|
|
75
|
-
const rect = map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start);
|
|
76
|
-
const seen: Record<number, boolean> = {},
|
|
77
|
-
rows = [];
|
|
78
|
-
for (let row = rect.top; row < rect.bottom; row++) {
|
|
79
|
-
const rowContent = [];
|
|
80
|
-
for (let index = row * map.width + rect.left, col = rect.left; col < rect.right; col++, index++) {
|
|
81
|
-
const pos = map.map[index] as number;
|
|
82
|
-
if (!seen[pos]) {
|
|
83
|
-
seen[pos] = true;
|
|
84
|
-
const cellRect = map.findCell(pos);
|
|
85
|
-
let cell = table.nodeAt(pos) as Node;
|
|
86
|
-
const extraLeft = rect.left - cellRect.left,
|
|
87
|
-
extraRight = cellRect.right - rect.right;
|
|
88
|
-
if (extraLeft > 0 || extraRight > 0) {
|
|
89
|
-
let attrs = cell.attrs;
|
|
90
|
-
if (extraLeft > 0) attrs = removeColSpan(attrs, 0, extraLeft);
|
|
91
|
-
if (extraRight > 0) attrs = removeColSpan(attrs, attrs['colspan'] - extraRight, extraRight);
|
|
92
|
-
if (cellRect.left < rect.left) cell = cell.type.createAndFill(attrs) as Node;
|
|
93
|
-
else cell = cell.type.create(attrs, cell.content);
|
|
94
|
-
}
|
|
95
|
-
if (cellRect.top < rect.top || cellRect.bottom > rect.bottom) {
|
|
96
|
-
const attrs = setAttr(
|
|
97
|
-
cell.attrs,
|
|
98
|
-
'rowspan',
|
|
99
|
-
Math.min(cellRect.bottom, rect.bottom) - Math.max(cellRect.top, rect.top),
|
|
100
|
-
);
|
|
101
|
-
if (cellRect.top < rect.top) cell = cell.type.createAndFill(attrs) as Node;
|
|
102
|
-
else cell = cell.type.create(attrs, cell.content);
|
|
103
|
-
}
|
|
104
|
-
rowContent.push(cell);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
rows.push(table.child(row).copy(Fragment.from(rowContent)));
|
|
108
|
-
}
|
|
119
|
+
const fragment = this.isColSelection() && this.isRowSelection() ? table : rows
|
|
120
|
+
return new Slice(Fragment.from(fragment), 1, 1)
|
|
121
|
+
}
|
|
109
122
|
|
|
110
|
-
|
|
111
|
-
|
|
123
|
+
override replace(tr: Transaction, content = Slice.empty) {
|
|
124
|
+
const mapFrom = tr.steps.length
|
|
125
|
+
const ranges = this.ranges
|
|
126
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
127
|
+
const { $from, $to } = ranges[i] as SelectionRange
|
|
128
|
+
const mapping = tr.mapping.slice(mapFrom)
|
|
129
|
+
tr.replace(mapping.map($from.pos), mapping.map($to.pos), i ? Slice.empty : content)
|
|
112
130
|
}
|
|
131
|
+
const sel = Selection.findFrom(tr.doc.resolve(tr.mapping.slice(mapFrom).map(this.to)), -1)
|
|
132
|
+
if (sel)
|
|
133
|
+
tr.setSelection(sel)
|
|
134
|
+
}
|
|
113
135
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
for (let i = 0; i < ranges.length; i++) {
|
|
118
|
-
const { $from, $to } = ranges[i] as SelectionRange,
|
|
119
|
-
mapping = tr.mapping.slice(mapFrom);
|
|
120
|
-
tr.replace(mapping.map($from.pos), mapping.map($to.pos), i ? Slice.empty : content);
|
|
121
|
-
}
|
|
122
|
-
const sel = Selection.findFrom(tr.doc.resolve(tr.mapping.slice(mapFrom).map(this.to)), -1);
|
|
123
|
-
if (sel) tr.setSelection(sel);
|
|
124
|
-
}
|
|
136
|
+
override replaceWith(tr: Transaction, node: Node) {
|
|
137
|
+
this.replace(tr, new Slice(Fragment.from(node), 0, 0))
|
|
138
|
+
}
|
|
125
139
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
140
|
+
forEachCell(f: (node: Node, index: number) => void) {
|
|
141
|
+
const table = this.$anchorCell.node(-1)
|
|
142
|
+
const map = TableMap.get(table)
|
|
143
|
+
const start = this.$anchorCell.start(-1)
|
|
144
|
+
const cells = map.cellsInRect(map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start))
|
|
145
|
+
for (let i = 0; i < cells.length; i++)
|
|
146
|
+
f(table.nodeAt(cells[i] as number) as Node, start + (cells[i] as number))
|
|
147
|
+
}
|
|
129
148
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
149
|
+
// :: () → bool
|
|
150
|
+
// True if this selection goes all the way from the top to the
|
|
151
|
+
// bottom of the table.
|
|
152
|
+
isColSelection() {
|
|
153
|
+
const anchorTop = this.$anchorCell.index(-1)
|
|
154
|
+
const headTop = this.$headCell.index(-1)
|
|
155
|
+
if (Math.min(anchorTop, headTop) > 0)
|
|
156
|
+
return false
|
|
157
|
+
const anchorBot = anchorTop + (this.$anchorCell.nodeAfter as Node).attrs.rowspan
|
|
158
|
+
const headBot = headTop + (this.$headCell.nodeAfter as Node).attrs.rowspan
|
|
159
|
+
return Math.max(anchorBot, headBot) == this.$headCell.node(-1).childCount
|
|
160
|
+
}
|
|
138
161
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
162
|
+
// :: (ResolvedPos, ?ResolvedPos) → CellSelection
|
|
163
|
+
// Returns the smallest column selection that covers the given anchor
|
|
164
|
+
// and head cell.
|
|
165
|
+
static colSelection($anchorCell: ResolvedPos, $headCell = $anchorCell) {
|
|
166
|
+
const map = TableMap.get($anchorCell.node(-1))
|
|
167
|
+
const start = $anchorCell.start(-1)
|
|
168
|
+
const anchorRect = map.findCell($anchorCell.pos - start)
|
|
169
|
+
const headRect = map.findCell($headCell.pos - start)
|
|
170
|
+
const doc = $anchorCell.node(0)
|
|
171
|
+
if (anchorRect.top <= headRect.top) {
|
|
172
|
+
if (anchorRect.top > 0) {
|
|
173
|
+
const left = map.map[anchorRect.left] as number
|
|
174
|
+
$anchorCell = doc.resolve(start + left)
|
|
175
|
+
}
|
|
176
|
+
if (headRect.bottom < map.height) {
|
|
177
|
+
const pos = map.map[map.width * (map.height - 1) + headRect.right - 1] as number
|
|
178
|
+
$headCell = doc.resolve(start + pos)
|
|
179
|
+
}
|
|
149
180
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const doc = $anchorCell.node(0);
|
|
160
|
-
if (anchorRect.top <= headRect.top) {
|
|
161
|
-
if (anchorRect.top > 0) {
|
|
162
|
-
const left = map.map[anchorRect.left] as number;
|
|
163
|
-
$anchorCell = doc.resolve(start + left);
|
|
164
|
-
}
|
|
165
|
-
if (headRect.bottom < map.height) {
|
|
166
|
-
const pos = map.map[map.width * (map.height - 1) + headRect.right - 1] as number;
|
|
167
|
-
$headCell = doc.resolve(start + pos);
|
|
168
|
-
}
|
|
169
|
-
} else {
|
|
170
|
-
if (headRect.top > 0) {
|
|
171
|
-
const left = map.map[anchorRect.left] as number;
|
|
172
|
-
$headCell = doc.resolve(start + left);
|
|
173
|
-
}
|
|
174
|
-
if (anchorRect.bottom < map.height) {
|
|
175
|
-
const pos = map.map[map.width * (map.height - 1) + anchorRect.right - 1] as number;
|
|
176
|
-
$anchorCell = doc.resolve(start + pos);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return new CellSelection($anchorCell, $headCell);
|
|
181
|
+
else {
|
|
182
|
+
if (headRect.top > 0) {
|
|
183
|
+
const left = map.map[anchorRect.left] as number
|
|
184
|
+
$headCell = doc.resolve(start + left)
|
|
185
|
+
}
|
|
186
|
+
if (anchorRect.bottom < map.height) {
|
|
187
|
+
const pos = map.map[map.width * (map.height - 1) + anchorRect.right - 1] as number
|
|
188
|
+
$anchorCell = doc.resolve(start + pos)
|
|
189
|
+
}
|
|
180
190
|
}
|
|
191
|
+
return new CellSelection($anchorCell, $headCell)
|
|
192
|
+
}
|
|
181
193
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
// :: () → bool
|
|
195
|
+
// True if this selection goes all the way from the left to the
|
|
196
|
+
// right of the table.
|
|
197
|
+
isRowSelection() {
|
|
198
|
+
const map = TableMap.get(this.$anchorCell.node(-1))
|
|
199
|
+
const start = this.$anchorCell.start(-1)
|
|
200
|
+
const anchorLeft = map.colCount(this.$anchorCell.pos - start)
|
|
201
|
+
const headLeft = map.colCount(this.$headCell.pos - start)
|
|
202
|
+
if (Math.min(anchorLeft, headLeft) > 0)
|
|
203
|
+
return false
|
|
204
|
+
const anchorRight = anchorLeft + (this.$anchorCell.nodeAfter as Node).attrs.colspan
|
|
205
|
+
const headRight = headLeft + (this.$headCell.nodeAfter as Node).attrs.colspan
|
|
206
|
+
return Math.max(anchorRight, headRight) == map.width
|
|
207
|
+
}
|
|
195
208
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
other.$anchorCell.pos == this.$anchorCell.pos
|
|
200
|
-
other.$headCell.pos == this.$headCell.pos
|
|
201
|
-
|
|
202
|
-
|
|
209
|
+
eq(other: Selection): boolean {
|
|
210
|
+
return (
|
|
211
|
+
other instanceof CellSelection
|
|
212
|
+
&& other.$anchorCell.pos == this.$anchorCell.pos
|
|
213
|
+
&& other.$headCell.pos == this.$headCell.pos
|
|
214
|
+
)
|
|
215
|
+
}
|
|
203
216
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
} else {
|
|
223
|
-
if (headRect.left > 0) {
|
|
224
|
-
const pos = map.map[headRect.top * map.width] as number;
|
|
225
|
-
$headCell = doc.resolve(start + pos);
|
|
226
|
-
}
|
|
227
|
-
if (anchorRect.right < map.width) {
|
|
228
|
-
const pos = map.map[map.width * (anchorRect.top + 1) - 1] as number;
|
|
229
|
-
|
|
230
|
-
$anchorCell = doc.resolve(start + pos);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return new CellSelection($anchorCell, $headCell);
|
|
217
|
+
// :: (ResolvedPos, ?ResolvedPos) → CellSelection
|
|
218
|
+
// Returns the smallest row selection that covers the given anchor
|
|
219
|
+
// and head cell.
|
|
220
|
+
static rowSelection($anchorCell: ResolvedPos, $headCell = $anchorCell) {
|
|
221
|
+
const map = TableMap.get($anchorCell.node(-1))
|
|
222
|
+
const start = $anchorCell.start(-1)
|
|
223
|
+
const anchorRect = map.findCell($anchorCell.pos - start)
|
|
224
|
+
const headRect = map.findCell($headCell.pos - start)
|
|
225
|
+
const doc = $anchorCell.node(0)
|
|
226
|
+
if (anchorRect.left <= headRect.left) {
|
|
227
|
+
if (anchorRect.left > 0) {
|
|
228
|
+
const pos = map.map[anchorRect.top * map.width] as number
|
|
229
|
+
$anchorCell = doc.resolve(start + pos)
|
|
230
|
+
}
|
|
231
|
+
if (headRect.right < map.width) {
|
|
232
|
+
const pos = map.map[map.width * (headRect.top + 1) - 1] as number
|
|
233
|
+
$headCell = doc.resolve(start + pos)
|
|
234
|
+
}
|
|
234
235
|
}
|
|
236
|
+
else {
|
|
237
|
+
if (headRect.left > 0) {
|
|
238
|
+
const pos = map.map[headRect.top * map.width] as number
|
|
239
|
+
$headCell = doc.resolve(start + pos)
|
|
240
|
+
}
|
|
241
|
+
if (anchorRect.right < map.width) {
|
|
242
|
+
const pos = map.map[map.width * (anchorRect.top + 1) - 1] as number
|
|
235
243
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
type: 'cell',
|
|
239
|
-
anchor: this.$anchorCell.pos,
|
|
240
|
-
head: this.$headCell.pos,
|
|
241
|
-
};
|
|
244
|
+
$anchorCell = doc.resolve(start + pos)
|
|
245
|
+
}
|
|
242
246
|
}
|
|
247
|
+
return new CellSelection($anchorCell, $headCell)
|
|
248
|
+
}
|
|
243
249
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
250
|
+
toJSON() {
|
|
251
|
+
return {
|
|
252
|
+
type: 'cell',
|
|
253
|
+
anchor: this.$anchorCell.pos,
|
|
254
|
+
head: this.$headCell.pos,
|
|
247
255
|
}
|
|
256
|
+
}
|
|
248
257
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
258
|
+
static override fromJSON(doc: Node, json: any) {
|
|
259
|
+
return new CellSelection(doc.resolve(json.anchor), doc.resolve(json.head))
|
|
260
|
+
}
|
|
253
261
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
262
|
+
// :: (Node, number, ?number) → CellSelection
|
|
263
|
+
static create(doc: Node, anchorCell: number, headCell = anchorCell) {
|
|
264
|
+
return new CellSelection(doc.resolve(anchorCell), doc.resolve(headCell))
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
override getBookmark() {
|
|
268
|
+
return new CellBookmark(this.$anchorCell.pos, this.$headCell.pos)
|
|
269
|
+
}
|
|
257
270
|
}
|
|
258
271
|
|
|
259
|
-
CellSelection.prototype.visible = false
|
|
272
|
+
CellSelection.prototype.visible = false
|
|
260
273
|
|
|
261
|
-
Selection.jsonID('cell', CellSelection)
|
|
274
|
+
Selection.jsonID('cell', CellSelection)
|
|
262
275
|
|
|
263
276
|
class CellBookmark {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
277
|
+
constructor(public anchor: number, public head: number) {
|
|
278
|
+
this.anchor = anchor
|
|
279
|
+
this.head = head
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
map(mapping: Mappable) {
|
|
283
|
+
return new CellBookmark(mapping.map(this.anchor), mapping.map(this.head))
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
resolve(doc: Node): Selection {
|
|
287
|
+
const $anchorCell = doc.resolve(this.anchor)
|
|
288
|
+
const $headCell = doc.resolve(this.head)
|
|
289
|
+
if (
|
|
290
|
+
$anchorCell.parent.type.spec.tableRole == 'row'
|
|
291
|
+
&& $headCell.parent.type.spec.tableRole == 'row'
|
|
292
|
+
&& $anchorCell.index() < $anchorCell.parent.childCount
|
|
293
|
+
&& $headCell.index() < $headCell.parent.childCount
|
|
294
|
+
&& inSameTable($anchorCell, $headCell)
|
|
295
|
+
)
|
|
296
|
+
return new CellSelection($anchorCell, $headCell)
|
|
297
|
+
else return Selection.near($headCell, 1)
|
|
298
|
+
}
|
|
284
299
|
}
|
|
285
300
|
|
|
286
301
|
export function drawCellSelection(state: EditorState) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
})
|
|
292
|
-
|
|
302
|
+
if (!(state.selection instanceof CellSelection))
|
|
303
|
+
return null
|
|
304
|
+
const cells: Decoration[] = []
|
|
305
|
+
state.selection.forEachCell((node, pos) => {
|
|
306
|
+
cells.push(Decoration.node(pos, pos + node.nodeSize, { class: 'selectedCell' }))
|
|
307
|
+
})
|
|
308
|
+
return DecorationSet.create(state.doc, cells)
|
|
293
309
|
}
|
|
294
310
|
|
|
295
311
|
function isCellBoundarySelection({ $from, $to }: Selection) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
312
|
+
if ($from.pos == $to.pos || $from.pos < $from.pos - 6)
|
|
313
|
+
return false // Cheap elimination
|
|
314
|
+
let afterFrom = $from.pos
|
|
315
|
+
let beforeTo = $to.pos
|
|
316
|
+
let depth = $from.depth
|
|
317
|
+
for (; depth >= 0; depth--, afterFrom++) {
|
|
318
|
+
if ($from.after(depth + 1) < $from.end(depth))
|
|
319
|
+
break
|
|
320
|
+
}
|
|
321
|
+
for (let d = $to.depth; d >= 0; d--, beforeTo--) {
|
|
322
|
+
if ($to.before(d + 1) > $to.start(d))
|
|
323
|
+
break
|
|
324
|
+
}
|
|
325
|
+
return afterFrom == beforeTo && /row|table/.test($from.node(depth).type.spec.tableRole)
|
|
303
326
|
}
|
|
304
327
|
|
|
305
328
|
function isTextSelectionAcrossCells({ $from, $to }: Selection) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
329
|
+
let fromCellBoundaryNode
|
|
330
|
+
let toCellBoundaryNode
|
|
331
|
+
|
|
332
|
+
for (let i = $from.depth; i > 0; i--) {
|
|
333
|
+
const node = $from.node(i)
|
|
334
|
+
if (node.type.spec.tableRole === 'cell' || node.type.spec.tableRole === 'header_cell') {
|
|
335
|
+
fromCellBoundaryNode = node
|
|
336
|
+
break
|
|
315
337
|
}
|
|
338
|
+
}
|
|
316
339
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
340
|
+
for (let i = $to.depth; i > 0; i--) {
|
|
341
|
+
const node = $to.node(i)
|
|
342
|
+
if (node.type.spec.tableRole === 'cell' || node.type.spec.tableRole === 'header_cell') {
|
|
343
|
+
toCellBoundaryNode = node
|
|
344
|
+
break
|
|
323
345
|
}
|
|
346
|
+
}
|
|
324
347
|
|
|
325
|
-
|
|
348
|
+
return fromCellBoundaryNode !== toCellBoundaryNode && $to.parentOffset === 0
|
|
326
349
|
}
|
|
327
350
|
|
|
328
351
|
export function normalizeSelection(state: EditorState, tr: Transaction | undefined, allowTableNodeSelection: boolean) {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
} else if (sel instanceof TextSelection && isTextSelectionAcrossCells(sel)) {
|
|
348
|
-
normalize = TextSelection.create(doc, sel.$from.start(), sel.$from.end());
|
|
352
|
+
const sel = (tr || state).selection
|
|
353
|
+
const doc = (tr || state).doc
|
|
354
|
+
let normalize, role
|
|
355
|
+
// eslint-disable-next-line no-cond-assign
|
|
356
|
+
if (sel instanceof NodeSelection && (role = sel.node.type.spec.tableRole)) {
|
|
357
|
+
if (role == 'cell' || role == 'header_cell') {
|
|
358
|
+
normalize = CellSelection.create(doc, sel.from)
|
|
359
|
+
}
|
|
360
|
+
else if (role == 'row') {
|
|
361
|
+
const $cell = doc.resolve(sel.from + 1)
|
|
362
|
+
normalize = CellSelection.rowSelection($cell, $cell)
|
|
363
|
+
}
|
|
364
|
+
else if (!allowTableNodeSelection) {
|
|
365
|
+
const map = TableMap.get(sel.node)
|
|
366
|
+
const start = sel.from + 1
|
|
367
|
+
const pos = map.map[map.width * map.height - 1] as number
|
|
368
|
+
const lastCell = start + pos
|
|
369
|
+
normalize = CellSelection.create(doc, start + 1, lastCell)
|
|
349
370
|
}
|
|
350
|
-
|
|
351
|
-
|
|
371
|
+
}
|
|
372
|
+
else if (sel instanceof TextSelection && isCellBoundarySelection(sel)) {
|
|
373
|
+
normalize = TextSelection.create(doc, sel.from)
|
|
374
|
+
}
|
|
375
|
+
else if (sel instanceof TextSelection && isTextSelectionAcrossCells(sel)) {
|
|
376
|
+
normalize = TextSelection.create(doc, sel.$from.start(), sel.$from.end())
|
|
377
|
+
}
|
|
378
|
+
if (normalize)
|
|
379
|
+
(tr || (tr = state.tr)).setSelection(normalize)
|
|
380
|
+
return tr
|
|
352
381
|
}
|