@milkdown/preset-gfm 6.5.0 → 6.5.3
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 +1007 -863
- 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 +17 -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 -24
- 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,400 +1,432 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import {
|
|
3
|
+
import type { Node, NodeSpec, NodeType, ResolvedPos } from '@milkdown/prose/model'
|
|
4
|
+
import { Fragment } from '@milkdown/prose/model'
|
|
5
|
+
import type { Command, EditorState, Transaction } from '@milkdown/prose/state'
|
|
6
|
+
import { TextSelection } from '@milkdown/prose/state'
|
|
7
|
+
|
|
8
|
+
import { CellSelection } from './cell-selection'
|
|
9
|
+
import { tableNodeTypes } from './schema'
|
|
10
|
+
import { Rect, TableMap } from './table-map'
|
|
9
11
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from './util'
|
|
12
|
+
addColSpan,
|
|
13
|
+
cellAround,
|
|
14
|
+
cellWrapping,
|
|
15
|
+
columnIsHeader,
|
|
16
|
+
isInTable,
|
|
17
|
+
moveCellForward,
|
|
18
|
+
removeColSpan,
|
|
19
|
+
selectionCell,
|
|
20
|
+
setAttr,
|
|
21
|
+
} from './util'
|
|
20
22
|
|
|
21
23
|
// Helper to get the selected rectangle in a table, if any. Adds table
|
|
22
24
|
// map, table node, and table start offset to the object for
|
|
23
25
|
// convenience.
|
|
24
26
|
export function selectedRect(state: EditorState): Required<Rect> {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
const sel = state.selection
|
|
28
|
+
const $pos = selectionCell(state) as ResolvedPos
|
|
29
|
+
const table = $pos.node(-1)
|
|
30
|
+
const tableStart = $pos.start(-1)
|
|
31
|
+
const map = TableMap.get(table)
|
|
32
|
+
let rect
|
|
33
|
+
if (sel instanceof CellSelection)
|
|
34
|
+
rect = map.rectBetween(sel.$anchorCell.pos - tableStart, sel.$headCell.pos - tableStart)
|
|
35
|
+
else rect = map.findCell($pos.pos - tableStart)
|
|
36
|
+
rect.tableStart = tableStart
|
|
37
|
+
rect.map = map
|
|
38
|
+
rect.table = table
|
|
39
|
+
return rect as Required<Rect>
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
// Add a column at the given position in a table.
|
|
41
43
|
export function addColumn(tr: Transaction, { map, tableStart, table }: Rect, col: number) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const offset = map.map[index + (refColumn as number)] as number;
|
|
59
|
-
const type =
|
|
60
|
-
refColumn == null ? tableNodeTypes(table.type.schema).cell : (table.nodeAt(offset) as Node).type;
|
|
61
|
-
const pos = map.positionAt(row, col, table);
|
|
62
|
-
tr.insert(tr.mapping.map(tableStart + pos), type.createAndFill());
|
|
63
|
-
}
|
|
44
|
+
map = map as TableMap
|
|
45
|
+
table = table as Node
|
|
46
|
+
tableStart = tableStart as number
|
|
47
|
+
let refColumn: number | null = col > 0 ? -1 : 0
|
|
48
|
+
if (columnIsHeader(map, table, col + refColumn))
|
|
49
|
+
refColumn = col == 0 || col == map.width ? null : 0
|
|
50
|
+
|
|
51
|
+
for (let row = 0; row < map.height; row++) {
|
|
52
|
+
const index = row * map.width + col
|
|
53
|
+
// If this position falls inside a col-spanning cell
|
|
54
|
+
if (col > 0 && col < map.width && map.map[index - 1] == map.map[index]) {
|
|
55
|
+
const pos = map.map[index] as number
|
|
56
|
+
const cell = table.nodeAt(pos) as Node
|
|
57
|
+
tr.setNodeMarkup(tr.mapping.map(tableStart + pos), null, addColSpan(cell.attrs, col - map.colCount(pos)))
|
|
58
|
+
// Skip ahead if rowspan > 1
|
|
59
|
+
row += cell.attrs.rowspan - 1
|
|
64
60
|
}
|
|
65
|
-
|
|
61
|
+
else {
|
|
62
|
+
const offset = map.map[index + (refColumn as number)] as number
|
|
63
|
+
const type
|
|
64
|
+
= refColumn == null ? tableNodeTypes(table.type.schema).cell : (table.nodeAt(offset) as Node).type
|
|
65
|
+
const pos = map.positionAt(row, col, table)
|
|
66
|
+
tr.insert(tr.mapping.map(tableStart + pos), type.createAndFill())
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return tr
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
69
73
|
// Command to add a column before the column with the selection.
|
|
70
74
|
export const addColumnBefore: Command = (state, dispatch) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
if (!isInTable(state))
|
|
76
|
+
return false
|
|
77
|
+
if (dispatch) {
|
|
78
|
+
const rect = selectedRect(state)
|
|
79
|
+
dispatch(addColumn(state.tr, rect, rect.left))
|
|
80
|
+
}
|
|
81
|
+
return true
|
|
82
|
+
}
|
|
78
83
|
|
|
79
84
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
80
85
|
// Command to add a column after the column with the selection.
|
|
81
86
|
export const addColumnAfter: Command = (state, dispatch) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
if (!isInTable(state))
|
|
88
|
+
return false
|
|
89
|
+
if (dispatch) {
|
|
90
|
+
const rect = selectedRect(state)
|
|
91
|
+
dispatch(addColumn(state.tr, rect, rect.right))
|
|
92
|
+
}
|
|
93
|
+
return true
|
|
94
|
+
}
|
|
89
95
|
|
|
90
96
|
export function removeColumn(tr: Transaction, { map, table, tableStart }: Rect, col: number) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
} else {
|
|
107
|
-
const start = tr.mapping.slice(mapStart).map(tableStart + pos);
|
|
108
|
-
tr.delete(start, start + cell.nodeSize);
|
|
109
|
-
}
|
|
110
|
-
row += cell.attrs['rowspan'];
|
|
97
|
+
map = map as TableMap
|
|
98
|
+
table = table as Node
|
|
99
|
+
tableStart = tableStart as number
|
|
100
|
+
const mapStart = tr.mapping.maps.length
|
|
101
|
+
for (let row = 0; row < map.height;) {
|
|
102
|
+
const index = row * map.width + col
|
|
103
|
+
const pos = map.map[index] as number
|
|
104
|
+
const cell = table.nodeAt(pos) as Node
|
|
105
|
+
// If this is part of a col-spanning cell
|
|
106
|
+
if ((col > 0 && map.map[index - 1] == pos) || (col < map.width - 1 && map.map[index + 1] == pos)) {
|
|
107
|
+
tr.setNodeMarkup(
|
|
108
|
+
tr.mapping.slice(mapStart).map(tableStart + pos),
|
|
109
|
+
null,
|
|
110
|
+
removeColSpan(cell.attrs, col - map.colCount(pos)),
|
|
111
|
+
)
|
|
111
112
|
}
|
|
113
|
+
else {
|
|
114
|
+
const start = tr.mapping.slice(mapStart).map(tableStart + pos)
|
|
115
|
+
tr.delete(start, start + cell.nodeSize)
|
|
116
|
+
}
|
|
117
|
+
row += cell.attrs.rowspan
|
|
118
|
+
}
|
|
112
119
|
}
|
|
113
120
|
|
|
114
121
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
115
122
|
// Command function that removes the selected columns from a table.
|
|
116
123
|
export const deleteColumn: Command = (state, dispatch) => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
if (!isInTable(state))
|
|
125
|
+
return false
|
|
126
|
+
if (dispatch) {
|
|
127
|
+
const rect = selectedRect(state) as Required<Rect>
|
|
128
|
+
const tr = state.tr
|
|
129
|
+
if (rect.left == 0 && rect.right == rect.map.width)
|
|
130
|
+
return false
|
|
131
|
+
for (let i = rect.right - 1; ; i--) {
|
|
132
|
+
removeColumn(tr, rect, i)
|
|
133
|
+
if (i == rect.left)
|
|
134
|
+
break
|
|
135
|
+
rect.table = (rect.tableStart ? tr.doc.nodeAt(rect.tableStart - 1) : tr.doc) as Node
|
|
136
|
+
rect.map = TableMap.get(rect.table)
|
|
129
137
|
}
|
|
130
|
-
|
|
131
|
-
}
|
|
138
|
+
dispatch(tr)
|
|
139
|
+
}
|
|
140
|
+
return true
|
|
141
|
+
}
|
|
132
142
|
|
|
133
143
|
export function rowIsHeader(map: TableMap, table: Node, row: number) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
const headerCell = tableNodeTypes(table.type.schema).header_cell
|
|
145
|
+
for (let col = 0; col < map.width; col++) {
|
|
146
|
+
const offset = map.map[col + row * map.width] as number
|
|
147
|
+
if ((table.nodeAt(offset) as Node).type != headerCell)
|
|
148
|
+
return false
|
|
149
|
+
}
|
|
150
|
+
return true
|
|
140
151
|
}
|
|
141
152
|
|
|
142
153
|
export function addRow(tr: Transaction, { map, tableStart, table }: Rect, row: number) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
map = map as TableMap
|
|
155
|
+
table = table as Node
|
|
156
|
+
tableStart = tableStart as number
|
|
157
|
+
let rowPos = tableStart
|
|
158
|
+
for (let i = 0; i < row; i++) rowPos += table.child(i).nodeSize
|
|
159
|
+
const cells = []
|
|
160
|
+
let refRow: number | null = row > 0 ? -1 : 0
|
|
161
|
+
if (rowIsHeader(map, table, row + refRow))
|
|
162
|
+
refRow = row == 0 || row == map.height ? null : 0
|
|
163
|
+
for (let col = 0, index = map.width * row; col < map.width; col++, index++) {
|
|
164
|
+
// Covered by a rowspan cell
|
|
165
|
+
if (row > 0 && row < map.height && map.map[index] == map.map[index - map.width]) {
|
|
166
|
+
const pos = map.map[index] as number
|
|
167
|
+
const attrs = (table.nodeAt(pos) as Node).attrs
|
|
168
|
+
tr.setNodeMarkup(tableStart + pos, null, setAttr(attrs, 'rowspan', attrs.rowspan + 1))
|
|
169
|
+
col += attrs.colspan - 1
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const type
|
|
173
|
+
= refRow == null
|
|
174
|
+
? tableNodeTypes(table.type.schema).cell
|
|
175
|
+
: (table.nodeAt(map.map[index + refRow * map.width] as number) as Node).type
|
|
176
|
+
cells.push(type.createAndFill())
|
|
165
177
|
}
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
}
|
|
179
|
+
tr.insert(rowPos, tableNodeTypes(table.type.schema).row.create(null, cells))
|
|
180
|
+
return tr
|
|
168
181
|
}
|
|
169
182
|
|
|
170
183
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
171
184
|
// Add a table row before the selection.
|
|
172
185
|
export function addRowBefore(state: EditorState, dispatch?: (tr: Transaction) => boolean) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
186
|
+
if (!isInTable(state))
|
|
187
|
+
return false
|
|
188
|
+
if (dispatch) {
|
|
189
|
+
const rect = selectedRect(state)
|
|
190
|
+
dispatch(addRow(state.tr, rect, rect.top))
|
|
191
|
+
}
|
|
192
|
+
return true
|
|
179
193
|
}
|
|
180
194
|
|
|
181
195
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
182
196
|
// Add a table row after the selection.
|
|
183
197
|
export function addRowAfter(state: EditorState, dispatch?: (tr: Transaction) => boolean) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
198
|
+
if (!isInTable(state))
|
|
199
|
+
return false
|
|
200
|
+
if (dispatch) {
|
|
201
|
+
const rect = selectedRect(state)
|
|
202
|
+
dispatch(addRow(state.tr, rect, rect.bottom))
|
|
203
|
+
}
|
|
204
|
+
return true
|
|
190
205
|
}
|
|
191
206
|
|
|
192
207
|
export function removeRow(tr: Transaction, { map, tableStart, table }: Rect, row: number) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
} else if (row < map.width && pos == map.map[index + map.width]) {
|
|
215
|
-
// Else, if it continues in the row below, it has to be moved down
|
|
216
|
-
const cell = table.nodeAt(pos) as Node;
|
|
217
|
-
const copy = cell.type.create(setAttr(cell.attrs, 'rowspan', cell.attrs['rowspan'] - 1), cell.content);
|
|
218
|
-
const newPos = map.positionAt(row + 1, col, table);
|
|
219
|
-
tr.insert(tr.mapping.slice(mapFrom).map(tableStart + newPos), copy);
|
|
220
|
-
col += cell.attrs['colspan'] - 1;
|
|
221
|
-
}
|
|
208
|
+
map = map as TableMap
|
|
209
|
+
table = table as Node
|
|
210
|
+
tableStart = tableStart as number
|
|
211
|
+
let rowPos = 0
|
|
212
|
+
for (let i = 0; i < row; i++) rowPos += table.child(i).nodeSize
|
|
213
|
+
const nextRow = rowPos + table.child(row).nodeSize
|
|
214
|
+
|
|
215
|
+
const mapFrom = tr.mapping.maps.length
|
|
216
|
+
tr.delete(rowPos + tableStart, nextRow + tableStart)
|
|
217
|
+
|
|
218
|
+
for (let col = 0, index = row * map.width; col < map.width; col++, index++) {
|
|
219
|
+
const pos = map.map[index] as number
|
|
220
|
+
if (row > 0 && pos == map.map[index - map.width]) {
|
|
221
|
+
// If this cell starts in the row above, simply reduce its rowspan
|
|
222
|
+
const attrs = (table.nodeAt(pos) as Node).attrs
|
|
223
|
+
tr.setNodeMarkup(
|
|
224
|
+
tr.mapping.slice(mapFrom).map(pos + tableStart),
|
|
225
|
+
null,
|
|
226
|
+
setAttr(attrs, 'rowspan', attrs.rowspan - 1),
|
|
227
|
+
)
|
|
228
|
+
col += attrs.colspan - 1
|
|
222
229
|
}
|
|
230
|
+
else if (row < map.width && pos == map.map[index + map.width]) {
|
|
231
|
+
// Else, if it continues in the row below, it has to be moved down
|
|
232
|
+
const cell = table.nodeAt(pos) as Node
|
|
233
|
+
const copy = cell.type.create(setAttr(cell.attrs, 'rowspan', cell.attrs.rowspan - 1), cell.content)
|
|
234
|
+
const newPos = map.positionAt(row + 1, col, table)
|
|
235
|
+
tr.insert(tr.mapping.slice(mapFrom).map(tableStart + newPos), copy)
|
|
236
|
+
col += cell.attrs.colspan - 1
|
|
237
|
+
}
|
|
238
|
+
}
|
|
223
239
|
}
|
|
224
240
|
|
|
225
241
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
226
242
|
// Remove the selected rows from a table.
|
|
227
243
|
export const deleteRow: Command = (state, dispatch) => {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
244
|
+
if (!isInTable(state))
|
|
245
|
+
return false
|
|
246
|
+
if (dispatch) {
|
|
247
|
+
const rect = selectedRect(state) as Required<Rect>
|
|
248
|
+
const tr = state.tr
|
|
249
|
+
if (rect.top == 0 && rect.bottom == rect.map.height)
|
|
250
|
+
return false
|
|
251
|
+
for (let i = rect.bottom - 1; ; i--) {
|
|
252
|
+
removeRow(tr, rect, i)
|
|
253
|
+
if (i == rect.top)
|
|
254
|
+
break
|
|
255
|
+
rect.table = rect.tableStart ? (tr.doc.nodeAt(rect.tableStart - 1) as Node) : tr.doc
|
|
256
|
+
rect.map = TableMap.get(rect.table)
|
|
240
257
|
}
|
|
241
|
-
|
|
242
|
-
}
|
|
258
|
+
dispatch(tr)
|
|
259
|
+
}
|
|
260
|
+
return true
|
|
261
|
+
}
|
|
243
262
|
|
|
244
263
|
function isEmpty(cell: Node) {
|
|
245
|
-
|
|
246
|
-
|
|
264
|
+
const c = cell.content
|
|
265
|
+
return c.childCount == 1 && (c.firstChild as Node).isTextblock && (c.firstChild as Node).childCount == 0
|
|
247
266
|
}
|
|
248
267
|
|
|
249
268
|
function cellsOverlapRectangle({ width, height, map }: TableMap, rect: Rect) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
(rect.right < width && map[indexRight] == map[indexRight + 1])
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
(rect.bottom < height && map[indexBottom] == map[indexBottom + width])
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
let indexTop = rect.top * width + rect.left
|
|
270
|
+
let indexLeft = indexTop
|
|
271
|
+
let indexBottom = (rect.bottom - 1) * width + rect.left
|
|
272
|
+
let indexRight = indexTop + (rect.right - rect.left - 1)
|
|
273
|
+
for (let i = rect.top; i < rect.bottom; i++) {
|
|
274
|
+
if (
|
|
275
|
+
(rect.left > 0 && map[indexLeft] == map[indexLeft - 1])
|
|
276
|
+
|| (rect.right < width && map[indexRight] == map[indexRight + 1])
|
|
277
|
+
)
|
|
278
|
+
return true
|
|
279
|
+
indexLeft += width
|
|
280
|
+
indexRight += width
|
|
281
|
+
}
|
|
282
|
+
for (let i = rect.left; i < rect.right; i++) {
|
|
283
|
+
if (
|
|
284
|
+
(rect.top > 0 && map[indexTop] == map[indexTop - width])
|
|
285
|
+
|| (rect.bottom < height && map[indexBottom] == map[indexBottom + width])
|
|
286
|
+
)
|
|
287
|
+
return true
|
|
288
|
+
indexTop++
|
|
289
|
+
indexBottom++
|
|
290
|
+
}
|
|
291
|
+
return false
|
|
273
292
|
}
|
|
274
293
|
|
|
275
294
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
276
295
|
// Merge the selected cells into a single cell. Only available when
|
|
277
296
|
// the selected cells' outline forms a rectangle.
|
|
278
297
|
export function mergeCells(state: EditorState, dispatch?: (tr: Transaction) => boolean) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
tr.delete(mapped, mapped + cell.nodeSize);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
298
|
+
const sel = state.selection
|
|
299
|
+
if (!(sel instanceof CellSelection) || sel.$anchorCell.pos == sel.$headCell.pos)
|
|
300
|
+
return false
|
|
301
|
+
const rect = selectedRect(state) as Required<Rect>
|
|
302
|
+
const { map } = rect
|
|
303
|
+
if (cellsOverlapRectangle(map as TableMap, rect))
|
|
304
|
+
return false
|
|
305
|
+
if (dispatch) {
|
|
306
|
+
const tr = state.tr
|
|
307
|
+
const seen: Record<number, boolean> = {}
|
|
308
|
+
let content = Fragment.empty
|
|
309
|
+
let mergedPos
|
|
310
|
+
let mergedCell
|
|
311
|
+
for (let row = rect.top; row < rect.bottom; row++) {
|
|
312
|
+
for (let col = rect.left; col < rect.right; col++) {
|
|
313
|
+
const cellPos = map.map[row * map.width + col] as number
|
|
314
|
+
const cell = rect.table.nodeAt(cellPos) as Node
|
|
315
|
+
if (seen[cellPos])
|
|
316
|
+
continue
|
|
317
|
+
seen[cellPos] = true
|
|
318
|
+
if (mergedPos == null) {
|
|
319
|
+
mergedPos = cellPos
|
|
320
|
+
mergedCell = cell
|
|
305
321
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
setAttr(
|
|
312
|
-
addColSpan(
|
|
313
|
-
mergedCell.attrs,
|
|
314
|
-
mergedCell.attrs['colspan'],
|
|
315
|
-
rect.right - rect.left - mergedCell.attrs['colspan'],
|
|
316
|
-
),
|
|
317
|
-
'rowspan',
|
|
318
|
-
rect.bottom - rect.top,
|
|
319
|
-
),
|
|
320
|
-
);
|
|
321
|
-
if (content.size) {
|
|
322
|
-
const end = mergedPos + 1 + mergedCell.content.size;
|
|
323
|
-
const start = isEmpty(mergedCell) ? mergedPos + 1 : end;
|
|
324
|
-
tr.replaceWith(start + rect.tableStart, end + rect.tableStart, content);
|
|
322
|
+
else {
|
|
323
|
+
if (!isEmpty(cell))
|
|
324
|
+
content = content.append(cell.content)
|
|
325
|
+
const mapped = tr.mapping.map(cellPos + rect.tableStart)
|
|
326
|
+
tr.delete(mapped, mapped + cell.nodeSize)
|
|
325
327
|
}
|
|
326
|
-
|
|
327
|
-
dispatch(tr);
|
|
328
|
+
}
|
|
328
329
|
}
|
|
329
|
-
|
|
330
|
+
mergedCell = mergedCell as Node
|
|
331
|
+
mergedPos = mergedPos as number
|
|
332
|
+
tr.setNodeMarkup(
|
|
333
|
+
mergedPos + rect.tableStart,
|
|
334
|
+
null,
|
|
335
|
+
setAttr(
|
|
336
|
+
addColSpan(
|
|
337
|
+
mergedCell.attrs,
|
|
338
|
+
mergedCell.attrs.colspan,
|
|
339
|
+
rect.right - rect.left - mergedCell.attrs.colspan,
|
|
340
|
+
),
|
|
341
|
+
'rowspan',
|
|
342
|
+
rect.bottom - rect.top,
|
|
343
|
+
),
|
|
344
|
+
)
|
|
345
|
+
if (content.size) {
|
|
346
|
+
const end = mergedPos + 1 + mergedCell.content.size
|
|
347
|
+
const start = isEmpty(mergedCell) ? mergedPos + 1 : end
|
|
348
|
+
tr.replaceWith(start + rect.tableStart, end + rect.tableStart, content)
|
|
349
|
+
}
|
|
350
|
+
tr.setSelection(new CellSelection(tr.doc.resolve(mergedPos + rect.tableStart)))
|
|
351
|
+
dispatch(tr)
|
|
352
|
+
}
|
|
353
|
+
return true
|
|
330
354
|
}
|
|
331
355
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
332
356
|
// Split a selected cell, whose rowpan or colspan is greater than one,
|
|
333
357
|
// into smaller cells. Use the first cell type for the new cells.
|
|
334
358
|
export function splitCell(state: EditorState, dispatch?: (tr: Transaction) => boolean) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
359
|
+
const nodeTypes = tableNodeTypes(state.schema)
|
|
360
|
+
return splitCellWithType(({ node }) => {
|
|
361
|
+
return nodeTypes[node.type.spec.tableRole]
|
|
362
|
+
})(state, dispatch)
|
|
339
363
|
}
|
|
340
364
|
|
|
341
365
|
// :: (getCellType: ({ row: number, col: number, node: Node}) → NodeType) → (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
342
366
|
// Split a selected cell, whose rowpan or colspan is greater than one,
|
|
343
367
|
// into smaller cells with the cell type (th, td) returned by getType function.
|
|
344
368
|
export function splitCellWithType(getCellType: (pos: { row: number; col: number; node: Node }) => NodeType) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
tr.setSelection(new CellSelection(tr.doc.resolve(sel.$anchorCell.pos), pos));
|
|
393
|
-
}
|
|
394
|
-
dispatch(tr);
|
|
369
|
+
return (state: EditorState, dispatch?: (tr: Transaction) => boolean) => {
|
|
370
|
+
const sel = state.selection
|
|
371
|
+
let cellNode, cellPos
|
|
372
|
+
if (!(sel instanceof CellSelection)) {
|
|
373
|
+
cellNode = cellWrapping(sel.$from)
|
|
374
|
+
if (!cellNode)
|
|
375
|
+
return false
|
|
376
|
+
cellPos = (cellAround(sel.$from) as ResolvedPos).pos
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
if (sel.$anchorCell.pos != sel.$headCell.pos)
|
|
380
|
+
return false
|
|
381
|
+
cellNode = sel.$anchorCell.nodeAfter as Node
|
|
382
|
+
cellPos = sel.$anchorCell.pos
|
|
383
|
+
}
|
|
384
|
+
if (cellNode.attrs.colspan == 1 && cellNode.attrs.rowspan == 1)
|
|
385
|
+
return false
|
|
386
|
+
|
|
387
|
+
if (dispatch) {
|
|
388
|
+
let baseAttrs = cellNode.attrs
|
|
389
|
+
const attrs = []
|
|
390
|
+
const colwidth = baseAttrs.colwidth
|
|
391
|
+
if (baseAttrs.rowspan > 1)
|
|
392
|
+
baseAttrs = setAttr(baseAttrs, 'rowspan', 1)
|
|
393
|
+
if (baseAttrs.colspan > 1)
|
|
394
|
+
baseAttrs = setAttr(baseAttrs, 'colspan', 1)
|
|
395
|
+
const rect = selectedRect(state) as Required<Rect>
|
|
396
|
+
const tr = state.tr
|
|
397
|
+
for (let i = 0; i < rect.right - rect.left; i++) {
|
|
398
|
+
attrs.push(
|
|
399
|
+
colwidth
|
|
400
|
+
? setAttr(baseAttrs, 'colwidth', colwidth && colwidth[i] ? [colwidth[i]] : null)
|
|
401
|
+
: baseAttrs,
|
|
402
|
+
)
|
|
403
|
+
}
|
|
404
|
+
let lastCell
|
|
405
|
+
for (let row = rect.top; row < rect.bottom; row++) {
|
|
406
|
+
let pos = rect.map.positionAt(row, rect.left, rect.table)
|
|
407
|
+
if (row == rect.top)
|
|
408
|
+
pos += cellNode.nodeSize
|
|
409
|
+
for (let col = rect.left, i = 0; col < rect.right; col++, i++) {
|
|
410
|
+
if (col == rect.left && row == rect.top)
|
|
411
|
+
continue
|
|
412
|
+
tr.insert(
|
|
413
|
+
(lastCell = tr.mapping.map(pos + rect.tableStart, 1)),
|
|
414
|
+
getCellType({ node: cellNode, row, col }).createAndFill(attrs[i]) as Node,
|
|
415
|
+
)
|
|
395
416
|
}
|
|
396
|
-
|
|
397
|
-
|
|
417
|
+
}
|
|
418
|
+
tr.setNodeMarkup(cellPos, getCellType({ node: cellNode, row: rect.top, col: rect.left }), attrs[0])
|
|
419
|
+
if (sel instanceof CellSelection) {
|
|
420
|
+
let pos: ResolvedPos | undefined
|
|
421
|
+
if (lastCell)
|
|
422
|
+
pos = tr.doc.resolve(lastCell)
|
|
423
|
+
|
|
424
|
+
tr.setSelection(new CellSelection(tr.doc.resolve(sel.$anchorCell.pos), pos))
|
|
425
|
+
}
|
|
426
|
+
dispatch(tr)
|
|
427
|
+
}
|
|
428
|
+
return true
|
|
429
|
+
}
|
|
398
430
|
}
|
|
399
431
|
|
|
400
432
|
// :: (string, any) → (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
@@ -402,150 +434,161 @@ export function splitCellWithType(getCellType: (pos: { row: number; col: number;
|
|
|
402
434
|
// and is only available when the currently selected cell doesn't
|
|
403
435
|
// already have that attribute set to that value.
|
|
404
436
|
export function setCellAttr<T>(name: string, value: T): Command {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
|
|
437
|
+
return (state, dispatch) => {
|
|
438
|
+
if (!isInTable(state))
|
|
439
|
+
return false
|
|
440
|
+
const $cell = selectionCell(state) as ResolvedPos
|
|
441
|
+
if (($cell.nodeAfter as Node).attrs[name] === value)
|
|
442
|
+
return false
|
|
443
|
+
if (dispatch) {
|
|
444
|
+
const tr = state.tr
|
|
445
|
+
if (state.selection instanceof CellSelection) {
|
|
446
|
+
state.selection.forEachCell((node, pos) => {
|
|
447
|
+
if (node.attrs[name] !== value)
|
|
448
|
+
tr.setNodeMarkup(pos, null, setAttr(node.attrs, name, value))
|
|
449
|
+
})
|
|
450
|
+
}
|
|
451
|
+
else { tr.setNodeMarkup($cell.pos, null, setAttr(($cell.nodeAfter as Node).attrs, name, value)) }
|
|
452
|
+
dispatch(tr)
|
|
453
|
+
}
|
|
454
|
+
return true
|
|
455
|
+
}
|
|
420
456
|
}
|
|
421
457
|
|
|
422
458
|
function isHeaderEnabledByType(type: string, rect: Required<Rect>, types: Record<string, NodeSpec>) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
return true;
|
|
459
|
+
// Get cell positions for first row or first column
|
|
460
|
+
const cellPositions = rect.map.cellsInRect({
|
|
461
|
+
left: 0,
|
|
462
|
+
top: 0,
|
|
463
|
+
right: type == 'row' ? rect.map.width : 1,
|
|
464
|
+
bottom: type == 'column' ? rect.map.height : 1,
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
for (let i = 0; i < cellPositions.length; i++) {
|
|
468
|
+
const cell = rect.table.nodeAt(cellPositions[i] as number)
|
|
469
|
+
if (cell && cell.type !== types.header_cell)
|
|
470
|
+
return false
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return true
|
|
439
474
|
}
|
|
440
475
|
|
|
441
476
|
// Toggles between row/column header and normal cells (Only applies to first row/column).
|
|
442
477
|
// For deprecated behavior pass `useDeprecatedLogic` in options with true.
|
|
443
478
|
export function toggleHeader(type: string) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
479
|
+
return function (state: EditorState, dispatch?: (tr: Transaction) => boolean) {
|
|
480
|
+
if (!isInTable(state))
|
|
481
|
+
return false
|
|
482
|
+
if (dispatch) {
|
|
483
|
+
const types = tableNodeTypes(state.schema)
|
|
484
|
+
const rect = selectedRect(state)
|
|
485
|
+
const tr = state.tr
|
|
450
486
|
|
|
451
|
-
|
|
452
|
-
|
|
487
|
+
const isHeaderRowEnabled = isHeaderEnabledByType('row', rect, types)
|
|
488
|
+
const isHeaderColumnEnabled = isHeaderEnabledByType('column', rect, types)
|
|
453
489
|
|
|
454
|
-
|
|
455
|
-
type === 'column' ? isHeaderRowEnabled : type === 'row' ? isHeaderColumnEnabled : false
|
|
490
|
+
const isHeaderEnabled
|
|
491
|
+
= type === 'column' ? isHeaderRowEnabled : type === 'row' ? isHeaderColumnEnabled : false
|
|
456
492
|
|
|
457
|
-
|
|
493
|
+
const selectionStartsAt = isHeaderEnabled ? 1 : 0
|
|
458
494
|
|
|
459
|
-
|
|
460
|
-
type == 'column'
|
|
461
|
-
|
|
462
|
-
|
|
495
|
+
const cellsRect
|
|
496
|
+
= type == 'column'
|
|
497
|
+
? new Rect(0, selectionStartsAt, 1, rect.map.height)
|
|
498
|
+
: type == 'row'
|
|
463
499
|
? new Rect(selectionStartsAt, 0, rect.map.width, 1)
|
|
464
|
-
: rect
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
type == 'column'
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
500
|
+
: rect
|
|
501
|
+
|
|
502
|
+
const newType
|
|
503
|
+
= type == 'column'
|
|
504
|
+
? isHeaderColumnEnabled
|
|
505
|
+
? types.cell
|
|
506
|
+
: types.header_cell
|
|
507
|
+
: type == 'row'
|
|
472
508
|
? isHeaderRowEnabled
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
: types.cell
|
|
509
|
+
? types.cell
|
|
510
|
+
: types.header_cell
|
|
511
|
+
: types.cell
|
|
476
512
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
513
|
+
rect.map.cellsInRect(cellsRect).forEach((relativeCellPos) => {
|
|
514
|
+
const cellPos = relativeCellPos + rect.tableStart
|
|
515
|
+
const cell = tr.doc.nodeAt(cellPos)
|
|
480
516
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
});
|
|
517
|
+
if (cell)
|
|
518
|
+
tr.setNodeMarkup(cellPos, newType, cell.attrs)
|
|
519
|
+
})
|
|
485
520
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
521
|
+
dispatch(tr)
|
|
522
|
+
}
|
|
523
|
+
return true
|
|
524
|
+
}
|
|
490
525
|
}
|
|
491
526
|
|
|
492
527
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
493
528
|
// Toggles whether the selected row contains header cells.
|
|
494
|
-
export const toggleHeaderRow = toggleHeader('row')
|
|
529
|
+
export const toggleHeaderRow = toggleHeader('row')
|
|
495
530
|
|
|
496
531
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
497
532
|
// Toggles whether the selected column contains header cells.
|
|
498
|
-
export const toggleHeaderColumn = toggleHeader('column')
|
|
533
|
+
export const toggleHeaderColumn = toggleHeader('column')
|
|
499
534
|
|
|
500
535
|
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
|
|
501
536
|
// Toggles whether the selected cells are header cells.
|
|
502
|
-
export const toggleHeaderCell = toggleHeader('cell')
|
|
537
|
+
export const toggleHeaderCell = toggleHeader('cell')
|
|
503
538
|
|
|
504
539
|
function findNextCell($cell: ResolvedPos, dir: number) {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
540
|
+
if (dir < 0) {
|
|
541
|
+
const before = $cell.nodeBefore
|
|
542
|
+
if (before)
|
|
543
|
+
return $cell.pos - before.nodeSize
|
|
544
|
+
for (let row = $cell.index(-1) - 1, rowEnd = $cell.before(); row >= 0; row--) {
|
|
545
|
+
const rowNode = $cell.node(-1).child(row)
|
|
546
|
+
if (rowNode.childCount)
|
|
547
|
+
return rowEnd - 1 - (rowNode.lastChild as Node).nodeSize
|
|
548
|
+
rowEnd -= rowNode.nodeSize
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
if ($cell.index() < $cell.parent.childCount - 1)
|
|
553
|
+
return $cell.pos + ($cell.nodeAfter as Node).nodeSize
|
|
554
|
+
const table = $cell.node(-1)
|
|
555
|
+
for (let row = $cell.indexAfter(-1), rowStart = $cell.after(); row < table.childCount; row++) {
|
|
556
|
+
const rowNode = table.child(row)
|
|
557
|
+
if (rowNode.childCount)
|
|
558
|
+
return rowStart + 1
|
|
559
|
+
rowStart += rowNode.nodeSize
|
|
521
560
|
}
|
|
522
|
-
|
|
561
|
+
}
|
|
562
|
+
return undefined
|
|
523
563
|
}
|
|
524
564
|
|
|
525
565
|
// Returns a command for selecting the next (direction=1) or previous
|
|
526
566
|
// (direction=-1) cell in a table.
|
|
527
567
|
export function goToNextCell(direction: number): Command {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
}
|
|
568
|
+
return (state, dispatch) => {
|
|
569
|
+
if (!isInTable(state))
|
|
570
|
+
return false
|
|
571
|
+
const cell = findNextCell(selectionCell(state) as ResolvedPos, direction)
|
|
572
|
+
if (cell == null)
|
|
573
|
+
return false
|
|
574
|
+
if (dispatch) {
|
|
575
|
+
const $cell = state.doc.resolve(cell)
|
|
576
|
+
dispatch(state.tr.setSelection(TextSelection.between($cell, moveCellForward($cell))).scrollIntoView())
|
|
577
|
+
}
|
|
578
|
+
return true
|
|
579
|
+
}
|
|
538
580
|
}
|
|
539
581
|
|
|
540
582
|
// Deletes the table around the selection, if any.
|
|
541
583
|
export const deleteTable: Command = (state, dispatch) => {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
584
|
+
const $pos = state.selection.$anchor
|
|
585
|
+
for (let d = $pos.depth; d > 0; d--) {
|
|
586
|
+
const node = $pos.node(d)
|
|
587
|
+
if (node.type.spec.tableRole == 'table') {
|
|
588
|
+
if (dispatch)
|
|
589
|
+
dispatch(state.tr.delete($pos.before(d), $pos.after(d)).scrollIntoView())
|
|
590
|
+
return true
|
|
549
591
|
}
|
|
550
|
-
|
|
551
|
-
|
|
592
|
+
}
|
|
593
|
+
return false
|
|
594
|
+
}
|