@atlaskit/editor-tables 2.2.4 → 2.2.6
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/cjs/cell-bookmark.js +0 -10
- package/dist/cjs/cell-selection.js +37 -102
- package/dist/cjs/index.js +0 -4
- package/dist/cjs/pm-plugins/input.js +17 -83
- package/dist/cjs/pm-plugins/plugin-key.js +0 -2
- package/dist/cjs/pm-plugins/table-editing.js +17 -18
- package/dist/cjs/pm-plugins.js +0 -2
- package/dist/cjs/table-map.js +67 -138
- package/dist/cjs/utils/add-column-at.js +0 -9
- package/dist/cjs/utils/add-column.js +8 -24
- package/dist/cjs/utils/add-row-at.js +8 -37
- package/dist/cjs/utils/add-row.js +2 -23
- package/dist/cjs/utils/analytics-helpers.js +4 -15
- package/dist/cjs/utils/cells.js +0 -12
- package/dist/cjs/utils/clone-tr.js +0 -2
- package/dist/cjs/utils/colspan.js +2 -18
- package/dist/cjs/utils/copy-paste.js +51 -139
- package/dist/cjs/utils/create-table.js +14 -28
- package/dist/cjs/utils/draw-cell-selection.js +0 -4
- package/dist/cjs/utils/empty-cells.js +0 -6
- package/dist/cjs/utils/find.js +6 -18
- package/dist/cjs/utils/fix-tables.js +13 -56
- package/dist/cjs/utils/for-each-cell.js +3 -17
- package/dist/cjs/utils/get-cell-selection-ranges.js +2 -9
- package/dist/cjs/utils/get-cells-in-column.js +0 -7
- package/dist/cjs/utils/get-cells-in-row.js +0 -7
- package/dist/cjs/utils/get-cells-in-table.js +0 -8
- package/dist/cjs/utils/get-selection-range-in-column.js +6 -27
- package/dist/cjs/utils/get-selection-range-in-row.js +6 -27
- package/dist/cjs/utils/get-selection-rect.js +0 -7
- package/dist/cjs/utils/go-to-next-cell.js +3 -22
- package/dist/cjs/utils/handle-paste.js +5 -34
- package/dist/cjs/utils/is-selected.js +6 -23
- package/dist/cjs/utils/is-selection-type.js +0 -2
- package/dist/cjs/utils/move-column.js +0 -12
- package/dist/cjs/utils/move-row.js +0 -11
- package/dist/cjs/utils/normalize-selection.js +3 -27
- package/dist/cjs/utils/remove-column.js +10 -46
- package/dist/cjs/utils/remove-row.js +8 -49
- package/dist/cjs/utils/remove-table.js +0 -6
- package/dist/cjs/utils/reorder-utils.js +13 -37
- package/dist/cjs/utils/replace-table.js +0 -8
- package/dist/cjs/utils/select-nodes.js +11 -31
- package/dist/cjs/utils/selection-cell.js +0 -5
- package/dist/cjs/utils/selection-rect.js +0 -10
- package/dist/cjs/utils/set-cell-attrs.js +0 -4
- package/dist/cjs/utils/split-cell-with-type.js +2 -35
- package/dist/cjs/utils/split-cell.js +0 -4
- package/dist/cjs/utils/table-node-types.js +4 -8
- package/dist/cjs/utils/tables.js +0 -4
- package/dist/cjs/utils/test-utils.js +9 -26
- package/dist/cjs/utils/toggle-header.js +3 -16
- package/dist/cjs/utils/uuid.js +0 -3
- package/dist/cjs/utils.js +0 -42
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/cell-bookmark.js +0 -5
- package/dist/es2019/cell-selection.js +37 -81
- package/dist/es2019/index.js +1 -0
- package/dist/es2019/pm-plugins/input.js +15 -67
- package/dist/es2019/pm-plugins/table-editing.js +3 -12
- package/dist/es2019/table-map.js +57 -127
- package/dist/es2019/utils/add-column-at.js +2 -4
- package/dist/es2019/utils/add-column.js +6 -16
- package/dist/es2019/utils/add-row-at.js +8 -22
- package/dist/es2019/utils/add-row.js +2 -17
- package/dist/es2019/utils/analytics-helpers.js +0 -5
- package/dist/es2019/utils/cells.js +4 -9
- package/dist/es2019/utils/colspan.js +6 -11
- package/dist/es2019/utils/copy-paste.js +41 -115
- package/dist/es2019/utils/create-table.js +3 -12
- package/dist/es2019/utils/draw-cell-selection.js +0 -1
- package/dist/es2019/utils/empty-cells.js +2 -3
- package/dist/es2019/utils/find.js +8 -8
- package/dist/es2019/utils/fix-tables.js +17 -47
- package/dist/es2019/utils/for-each-cell.js +6 -11
- package/dist/es2019/utils/get-cell-selection-ranges.js +2 -4
- package/dist/es2019/utils/get-cells-in-column.js +2 -3
- package/dist/es2019/utils/get-cells-in-row.js +2 -3
- package/dist/es2019/utils/get-cells-in-table.js +2 -4
- package/dist/es2019/utils/get-selection-range-in-column.js +8 -22
- package/dist/es2019/utils/get-selection-range-in-row.js +8 -22
- package/dist/es2019/utils/get-selection-rect.js +2 -2
- package/dist/es2019/utils/go-to-next-cell.js +3 -19
- package/dist/es2019/utils/handle-paste.js +3 -14
- package/dist/es2019/utils/is-selected.js +8 -10
- package/dist/es2019/utils/is-selection-type.js +0 -1
- package/dist/es2019/utils/move-column.js +3 -8
- package/dist/es2019/utils/move-row.js +3 -7
- package/dist/es2019/utils/normalize-selection.js +0 -16
- package/dist/es2019/utils/remove-column.js +10 -27
- package/dist/es2019/utils/remove-row.js +12 -32
- package/dist/es2019/utils/remove-table.js +2 -4
- package/dist/es2019/utils/reorder-utils.js +11 -26
- package/dist/es2019/utils/replace-table.js +0 -2
- package/dist/es2019/utils/select-nodes.js +9 -20
- package/dist/es2019/utils/selection-cell.js +0 -2
- package/dist/es2019/utils/selection-rect.js +0 -4
- package/dist/es2019/utils/set-cell-attrs.js +2 -2
- package/dist/es2019/utils/split-cell-with-type.js +8 -28
- package/dist/es2019/utils/split-cell.js +3 -2
- package/dist/es2019/utils/table-node-types.js +4 -7
- package/dist/es2019/utils/tables.js +0 -2
- package/dist/es2019/utils/test-utils.js +12 -16
- package/dist/es2019/utils/toggle-header.js +3 -10
- package/dist/es2019/utils/uuid.js +0 -2
- package/dist/es2019/version.json +1 -1
- package/dist/esm/cell-bookmark.js +0 -5
- package/dist/esm/cell-selection.js +37 -79
- package/dist/esm/index.js +1 -0
- package/dist/esm/pm-plugins/input.js +17 -71
- package/dist/esm/pm-plugins/table-editing.js +8 -13
- package/dist/esm/table-map.js +68 -133
- package/dist/esm/utils/add-column-at.js +2 -4
- package/dist/esm/utils/add-column.js +8 -20
- package/dist/esm/utils/add-row-at.js +8 -23
- package/dist/esm/utils/add-row.js +2 -21
- package/dist/esm/utils/analytics-helpers.js +4 -10
- package/dist/esm/utils/cells.js +0 -5
- package/dist/esm/utils/colspan.js +2 -14
- package/dist/esm/utils/copy-paste.js +44 -125
- package/dist/esm/utils/create-table.js +14 -25
- package/dist/esm/utils/draw-cell-selection.js +0 -1
- package/dist/esm/utils/empty-cells.js +2 -3
- package/dist/esm/utils/find.js +8 -8
- package/dist/esm/utils/fix-tables.js +13 -49
- package/dist/esm/utils/for-each-cell.js +6 -11
- package/dist/esm/utils/get-cell-selection-ranges.js +2 -4
- package/dist/esm/utils/get-cells-in-column.js +2 -3
- package/dist/esm/utils/get-cells-in-row.js +2 -3
- package/dist/esm/utils/get-cells-in-table.js +2 -4
- package/dist/esm/utils/get-selection-range-in-column.js +8 -24
- package/dist/esm/utils/get-selection-range-in-row.js +8 -24
- package/dist/esm/utils/get-selection-rect.js +2 -2
- package/dist/esm/utils/go-to-next-cell.js +3 -19
- package/dist/esm/utils/handle-paste.js +5 -23
- package/dist/esm/utils/is-selected.js +8 -10
- package/dist/esm/utils/is-selection-type.js +0 -1
- package/dist/esm/utils/move-column.js +3 -8
- package/dist/esm/utils/move-row.js +3 -7
- package/dist/esm/utils/normalize-selection.js +3 -22
- package/dist/esm/utils/remove-column.js +10 -31
- package/dist/esm/utils/remove-row.js +8 -35
- package/dist/esm/utils/remove-table.js +2 -4
- package/dist/esm/utils/reorder-utils.js +11 -26
- package/dist/esm/utils/replace-table.js +0 -2
- package/dist/esm/utils/select-nodes.js +11 -22
- package/dist/esm/utils/selection-cell.js +0 -2
- package/dist/esm/utils/selection-rect.js +0 -4
- package/dist/esm/utils/set-cell-attrs.js +2 -2
- package/dist/esm/utils/split-cell-with-type.js +2 -28
- package/dist/esm/utils/split-cell.js +3 -2
- package/dist/esm/utils/table-node-types.js +4 -7
- package/dist/esm/utils/tables.js +0 -2
- package/dist/esm/utils/test-utils.js +12 -16
- package/dist/esm/utils/toggle-header.js +3 -10
- package/dist/esm/version.json +1 -1
- package/package.json +6 -4
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// cell selection is different, here the cells in the selection are
|
|
10
10
|
// clipped to the selection's rectangle, optionally repeating the
|
|
11
11
|
// pasted cells when they are smaller than the selection.
|
|
12
|
+
|
|
12
13
|
import { Fragment, Slice } from 'prosemirror-model';
|
|
13
14
|
import { Transform } from 'prosemirror-transform';
|
|
14
15
|
import { CellSelection } from '../cell-selection';
|
|
@@ -16,7 +17,9 @@ import { TableMap } from '../table-map';
|
|
|
16
17
|
import { removeColSpan } from './colspan';
|
|
17
18
|
import { selectedRect } from './selection-rect';
|
|
18
19
|
import { tableNodeTypes } from './table-node-types';
|
|
19
|
-
import { isHeaderEnabledByType } from './toggle-header';
|
|
20
|
+
import { isHeaderEnabledByType } from './toggle-header';
|
|
21
|
+
|
|
22
|
+
// Utilities to help with copying and pasting table cells
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Replace any header cells with table cells.
|
|
@@ -25,65 +28,55 @@ import { isHeaderEnabledByType } from './toggle-header'; // Utilities to help wi
|
|
|
25
28
|
* @param cells
|
|
26
29
|
* @returns Fragment with header cells converted to table cells
|
|
27
30
|
*/
|
|
28
|
-
|
|
29
31
|
function stripHeaderType(schema, cells) {
|
|
30
32
|
const newCells = [];
|
|
31
33
|
cells.forEach(cell => {
|
|
32
34
|
var _cellNodeType$createA;
|
|
33
|
-
|
|
34
35
|
// Convert to cell type if not already
|
|
35
36
|
const cellNodeType = tableNodeTypes(schema).cell;
|
|
36
37
|
const tableCell = cell.type === cellNodeType ? cell : (_cellNodeType$createA = cellNodeType.createAndFill(cell.attrs, cell.content, cell.marks)) !== null && _cellNodeType$createA !== void 0 ? _cellNodeType$createA : cell;
|
|
37
38
|
newCells.push(tableCell);
|
|
38
39
|
});
|
|
39
40
|
return Fragment.from(newCells);
|
|
40
|
-
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// : (Slice) → ?{width: number, height: number, rows: [Fragment]}
|
|
41
44
|
// Get a rectangular area of cells from a slice, or null if the outer
|
|
42
45
|
// nodes of the slice aren't table cells or rows.
|
|
43
|
-
|
|
44
|
-
|
|
45
46
|
export function pastedCells(slice) {
|
|
46
47
|
if (!slice.size) {
|
|
47
48
|
return null;
|
|
48
49
|
}
|
|
49
|
-
|
|
50
50
|
let {
|
|
51
51
|
content,
|
|
52
52
|
openStart,
|
|
53
53
|
openEnd
|
|
54
54
|
} = slice;
|
|
55
|
-
|
|
56
55
|
if (!content.firstChild) {
|
|
57
56
|
throw new Error('pastedCells: no firstChild defined for content');
|
|
58
57
|
}
|
|
59
|
-
|
|
60
58
|
while (content.childCount === 1 && (openStart > 0 && openEnd > 0 || content.firstChild.type.spec.tableRole === 'table')) {
|
|
61
59
|
openStart--;
|
|
62
60
|
openEnd--;
|
|
63
61
|
content = content.firstChild.content;
|
|
64
|
-
|
|
65
62
|
if (!content.firstChild) {
|
|
66
63
|
throw new Error('pastedCells: no firstChild defined for content');
|
|
67
64
|
}
|
|
68
65
|
}
|
|
69
|
-
|
|
70
66
|
const first = content.firstChild;
|
|
71
67
|
const role = first.type.spec.tableRole;
|
|
72
68
|
const {
|
|
73
69
|
schema
|
|
74
70
|
} = first.type;
|
|
75
71
|
const rows = [];
|
|
76
|
-
|
|
77
72
|
if (role === 'row') {
|
|
78
73
|
for (let i = 0; i < content.childCount; i++) {
|
|
79
74
|
let cells = content.child(i).content;
|
|
80
75
|
const left = i ? 0 : Math.max(0, openStart - 1);
|
|
81
76
|
const right = i < content.childCount - 1 ? 0 : Math.max(0, openEnd - 1);
|
|
82
|
-
|
|
83
77
|
if (left || right) {
|
|
84
78
|
cells = fitSlice(tableNodeTypes(schema).row, new Slice(cells, left, right)).content;
|
|
85
79
|
}
|
|
86
|
-
|
|
87
80
|
rows.push(cells);
|
|
88
81
|
}
|
|
89
82
|
} else if (role === 'cell' || role === 'header_cell') {
|
|
@@ -91,76 +84,64 @@ export function pastedCells(slice) {
|
|
|
91
84
|
} else {
|
|
92
85
|
return null;
|
|
93
86
|
}
|
|
94
|
-
|
|
95
87
|
const rowsWithoutHeaders = rows.map(row => stripHeaderType(schema, row));
|
|
96
88
|
return ensureRectangular(schema, rowsWithoutHeaders);
|
|
97
|
-
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// : (Schema, [Fragment]) → {width: number, height: number, rows: [Fragment]}
|
|
98
92
|
// Compute the width and height of a set of cells, and make sure each
|
|
99
93
|
// row has the same number of cells.
|
|
100
|
-
|
|
101
94
|
function ensureRectangular(schema, rowsFragment) {
|
|
102
95
|
const rows = rowsFragment;
|
|
103
96
|
const widths = [];
|
|
104
|
-
|
|
105
97
|
for (let i = 0; i < rows.length; i++) {
|
|
106
98
|
const row = rows[i];
|
|
107
|
-
|
|
108
99
|
for (let j = row.childCount - 1; j >= 0; j--) {
|
|
109
100
|
const {
|
|
110
101
|
rowspan,
|
|
111
102
|
colspan
|
|
112
103
|
} = row.child(j).attrs;
|
|
113
|
-
|
|
114
104
|
for (let r = i; r < i + rowspan; r++) {
|
|
115
105
|
widths[r] = (widths[r] || 0) + colspan;
|
|
116
106
|
}
|
|
117
107
|
}
|
|
118
108
|
}
|
|
119
|
-
|
|
120
109
|
let width = 0;
|
|
121
|
-
|
|
122
110
|
for (let r = 0; r < widths.length; r++) {
|
|
123
111
|
width = Math.max(width, widths[r]);
|
|
124
112
|
}
|
|
125
|
-
|
|
126
113
|
for (let r = 0; r < widths.length; r++) {
|
|
127
114
|
if (r >= rows.length) {
|
|
128
115
|
rows.push(Fragment.empty);
|
|
129
116
|
}
|
|
130
|
-
|
|
131
117
|
if (widths[r] < width) {
|
|
132
118
|
const empty = tableNodeTypes(schema).cell.createAndFill();
|
|
133
119
|
const cells = [];
|
|
134
|
-
|
|
135
120
|
for (let i = widths[r]; i < width; i++) {
|
|
136
121
|
cells.push(empty);
|
|
137
122
|
}
|
|
138
|
-
|
|
139
123
|
rows[r] = rows[r].append(Fragment.from(cells));
|
|
140
124
|
}
|
|
141
125
|
}
|
|
142
|
-
|
|
143
126
|
return {
|
|
144
127
|
height: rows.length,
|
|
145
128
|
width,
|
|
146
129
|
rows
|
|
147
130
|
};
|
|
148
131
|
}
|
|
149
|
-
|
|
150
132
|
export function fitSlice(nodeType, slice) {
|
|
151
133
|
const node = nodeType.createAndFill();
|
|
152
|
-
|
|
153
134
|
if (!node) {
|
|
154
135
|
throw new Error(`fitSlice: unable to create node`);
|
|
155
136
|
}
|
|
156
|
-
|
|
157
137
|
const tr = new Transform(node).replace(0, node.content.size, slice);
|
|
158
138
|
return tr.doc;
|
|
159
|
-
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// : ({width: number, height: number, rows: [Fragment]}, number, number) → {width: number, height: number, rows: [Fragment]}
|
|
160
142
|
// Clip or extend (repeat) the given set of cells to cover the given
|
|
161
143
|
// width and height. Will clip rowspan/colspan cells at the edges when
|
|
162
144
|
// they stick out.
|
|
163
|
-
|
|
164
145
|
export function clipCells({
|
|
165
146
|
width: currentWidth,
|
|
166
147
|
height: currentHeight,
|
|
@@ -169,71 +150,57 @@ export function clipCells({
|
|
|
169
150
|
let rows = currentRows;
|
|
170
151
|
let width = currentWidth;
|
|
171
152
|
let height = currentHeight;
|
|
172
|
-
|
|
173
153
|
if (width !== newWidth) {
|
|
174
154
|
const added = [];
|
|
175
155
|
const newRows = [];
|
|
176
|
-
|
|
177
156
|
for (let row = 0; row < rows.length; row++) {
|
|
178
157
|
const frag = rows[row];
|
|
179
158
|
const cells = [];
|
|
180
|
-
|
|
181
159
|
for (let col = added[row] || 0, i = 0; col < newWidth; i++) {
|
|
182
160
|
let cell = frag.child(i % frag.childCount);
|
|
183
|
-
|
|
184
161
|
if (col + cell.attrs.colspan > newWidth) {
|
|
185
162
|
cell = cell.type.create(removeColSpan(cell.attrs, cell.attrs.colspan, col + cell.attrs.colspan - newWidth), cell.content);
|
|
186
163
|
}
|
|
187
|
-
|
|
188
164
|
cells.push(cell);
|
|
189
165
|
col += cell.attrs.colspan;
|
|
190
|
-
|
|
191
166
|
for (let j = 1; j < cell.attrs.rowspan; j++) {
|
|
192
167
|
added[row + j] = (added[row + j] || 0) + cell.attrs.colspan;
|
|
193
168
|
}
|
|
194
169
|
}
|
|
195
|
-
|
|
196
170
|
newRows.push(Fragment.from(cells));
|
|
197
171
|
}
|
|
198
|
-
|
|
199
172
|
rows = newRows;
|
|
200
173
|
width = newWidth;
|
|
201
174
|
}
|
|
202
|
-
|
|
203
175
|
if (height !== newHeight) {
|
|
204
176
|
const newRows = [];
|
|
205
|
-
|
|
206
177
|
for (let row = 0, i = 0; row < newHeight; row++, i++) {
|
|
207
178
|
const cells = [];
|
|
208
179
|
const source = rows[i % height];
|
|
209
|
-
|
|
210
180
|
for (let j = 0; j < source.childCount; j++) {
|
|
211
181
|
let cell = source.child(j);
|
|
212
|
-
|
|
213
182
|
if (row + cell.attrs.rowspan > newHeight) {
|
|
214
|
-
cell = cell.type.create({
|
|
183
|
+
cell = cell.type.create({
|
|
184
|
+
...cell.attrs,
|
|
215
185
|
rowspan: Math.max(1, newHeight - cell.attrs.rowspan)
|
|
216
186
|
}, cell.content);
|
|
217
187
|
}
|
|
218
|
-
|
|
219
188
|
cells.push(cell);
|
|
220
189
|
}
|
|
221
|
-
|
|
222
190
|
newRows.push(Fragment.from(cells));
|
|
223
191
|
}
|
|
224
|
-
|
|
225
192
|
rows = newRows;
|
|
226
193
|
height = newHeight;
|
|
227
194
|
}
|
|
228
|
-
|
|
229
195
|
return {
|
|
230
196
|
width,
|
|
231
197
|
height,
|
|
232
198
|
rows
|
|
233
199
|
};
|
|
234
|
-
}
|
|
235
|
-
// true if something was changed.
|
|
200
|
+
}
|
|
236
201
|
|
|
202
|
+
// Make sure a table has at least the given width and height. Return
|
|
203
|
+
// true if something was changed.
|
|
237
204
|
function growTable(tr, map, table, start, width, height, mapFrom) {
|
|
238
205
|
const {
|
|
239
206
|
schema
|
|
@@ -241,195 +208,162 @@ function growTable(tr, map, table, start, width, height, mapFrom) {
|
|
|
241
208
|
const types = tableNodeTypes(schema);
|
|
242
209
|
let empty;
|
|
243
210
|
let emptyHead;
|
|
244
|
-
|
|
245
211
|
if (width > map.width) {
|
|
246
212
|
for (let row = 0, rowEnd = 0; row < map.height; row++) {
|
|
247
213
|
const rowNode = table.child(row);
|
|
248
214
|
rowEnd += rowNode.nodeSize;
|
|
249
215
|
const cells = [];
|
|
250
216
|
let add;
|
|
251
|
-
|
|
252
217
|
if (rowNode.lastChild == null || rowNode.lastChild.type === types.cell) {
|
|
253
218
|
add = empty || (empty = types.cell.createAndFill());
|
|
254
219
|
} else {
|
|
255
220
|
add = emptyHead || (emptyHead = types.header_cell.createAndFill());
|
|
256
221
|
}
|
|
257
|
-
|
|
258
222
|
for (let i = map.width; i < width; i++) {
|
|
259
223
|
cells.push(add);
|
|
260
224
|
}
|
|
261
|
-
|
|
262
225
|
tr.insert(tr.mapping.slice(mapFrom).map(rowEnd - 1 + start), cells);
|
|
263
226
|
}
|
|
264
227
|
}
|
|
265
|
-
|
|
266
228
|
if (height > map.height) {
|
|
267
229
|
const cells = [];
|
|
268
|
-
|
|
269
230
|
for (let i = 0, k = (map.height - 1) * map.width; i < Math.max(map.width, width); i++) {
|
|
270
231
|
let header;
|
|
271
|
-
|
|
272
232
|
if (i >= map.width) {
|
|
273
233
|
header = false;
|
|
274
234
|
} else {
|
|
275
235
|
const mappedPos = map.map[k + i];
|
|
276
236
|
const node = table.nodeAt(mappedPos);
|
|
277
|
-
|
|
278
237
|
if (!node) {
|
|
279
238
|
throw new Error(`growTable: no node found at pos ${mappedPos}`);
|
|
280
239
|
}
|
|
281
|
-
|
|
282
240
|
header = node.type === types.header_cell;
|
|
283
241
|
}
|
|
284
|
-
|
|
285
242
|
cells.push(header ? emptyHead || (emptyHead = types.header_cell.createAndFill()) : empty || (empty = types.cell.createAndFill()));
|
|
286
243
|
}
|
|
287
|
-
|
|
288
244
|
const emptyRow = types.row.create(null, Fragment.from(cells));
|
|
289
245
|
const rows = [];
|
|
290
|
-
|
|
291
246
|
for (let i = map.height; i < height; i++) {
|
|
292
247
|
rows.push(emptyRow);
|
|
293
248
|
}
|
|
294
|
-
|
|
295
249
|
tr.insert(tr.mapping.slice(mapFrom).map(start + table.nodeSize - 2), rows);
|
|
296
250
|
}
|
|
297
|
-
|
|
298
251
|
return !!(empty || emptyHead);
|
|
299
|
-
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Make sure the given line (left, top) to (right, top) doesn't cross
|
|
300
255
|
// any rowspan cells by splitting cells that cross it. Return true if
|
|
301
256
|
// something changed.
|
|
302
|
-
|
|
303
|
-
|
|
304
257
|
function isolateHorizontal(tr, map, table, start, left, right, top, mapFrom) {
|
|
305
258
|
if (top === 0 || top === map.height) {
|
|
306
259
|
return false;
|
|
307
260
|
}
|
|
308
|
-
|
|
309
261
|
let found = false;
|
|
310
|
-
|
|
311
262
|
for (let col = left; col < right; col++) {
|
|
312
263
|
const index = top * map.width + col;
|
|
313
264
|
const pos = map.map[index];
|
|
314
|
-
|
|
315
265
|
if (map.map[index - map.width] === pos) {
|
|
316
266
|
found = true;
|
|
317
267
|
const cell = table.nodeAt(pos);
|
|
318
|
-
|
|
319
268
|
if (!cell) {
|
|
320
269
|
throw new Error(`isolateHorizontal: no cell found at pos ${pos}`);
|
|
321
270
|
}
|
|
322
|
-
|
|
323
271
|
const {
|
|
324
272
|
top: cellTop,
|
|
325
273
|
left: cellLeft
|
|
326
274
|
} = map.findCell(pos);
|
|
327
|
-
tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + start), undefined, {
|
|
275
|
+
tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(pos + start), undefined, {
|
|
276
|
+
...cell.attrs,
|
|
328
277
|
rowspan: top - cellTop
|
|
329
278
|
});
|
|
330
|
-
const newCell = cell.type.createAndFill({
|
|
279
|
+
const newCell = cell.type.createAndFill({
|
|
280
|
+
...cell.attrs,
|
|
331
281
|
rowspan: cellTop + cell.attrs.rowspan - top
|
|
332
282
|
});
|
|
333
|
-
|
|
334
283
|
if (!newCell) {
|
|
335
284
|
throw new Error('isolateHorizontal: failed to create cell');
|
|
336
285
|
}
|
|
337
|
-
|
|
338
286
|
tr.insert(tr.mapping.slice(mapFrom).map(map.positionAt(top, cellLeft, table)), newCell);
|
|
339
287
|
col += cell.attrs.colspan - 1;
|
|
340
288
|
}
|
|
341
289
|
}
|
|
342
|
-
|
|
343
290
|
return found;
|
|
344
|
-
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Make sure the given line (left, top) to (left, bottom) doesn't
|
|
345
294
|
// cross any colspan cells by splitting cells that cross it. Return
|
|
346
295
|
// true if something changed.
|
|
347
|
-
|
|
348
|
-
|
|
349
296
|
function isolateVertical(tr, map, table, start, top, bottom, left, mapFrom) {
|
|
350
297
|
if (left === 0 || left === map.width) {
|
|
351
298
|
return false;
|
|
352
299
|
}
|
|
353
|
-
|
|
354
300
|
let found = false;
|
|
355
|
-
|
|
356
301
|
for (let row = top; row < bottom; row++) {
|
|
357
302
|
const index = row * map.width + left;
|
|
358
303
|
const pos = map.map[index];
|
|
359
|
-
|
|
360
304
|
if (map.map[index - 1] === pos) {
|
|
361
305
|
found = true;
|
|
362
306
|
const cell = table.nodeAt(pos);
|
|
363
|
-
|
|
364
307
|
if (!cell) {
|
|
365
308
|
throw new Error(`isolateVertical: could not find cell at pos ${pos}`);
|
|
366
309
|
}
|
|
367
|
-
|
|
368
310
|
const cellLeft = map.colCount(pos);
|
|
369
311
|
const updatePos = tr.mapping.slice(mapFrom).map(pos + start);
|
|
370
312
|
tr.setNodeMarkup(updatePos, undefined, removeColSpan(cell.attrs, left - cellLeft, cell.attrs.colspan - (left - cellLeft)));
|
|
371
313
|
const newCell = cell.type.createAndFill(removeColSpan(cell.attrs, 0, left - cellLeft));
|
|
372
|
-
|
|
373
314
|
if (!newCell) {
|
|
374
315
|
throw new Error('isolateVertical: failed to create cell');
|
|
375
316
|
}
|
|
376
|
-
|
|
377
317
|
tr.insert(updatePos + cell.nodeSize, newCell);
|
|
378
318
|
row += cell.attrs.rowspan - 1;
|
|
379
319
|
}
|
|
380
320
|
}
|
|
381
|
-
|
|
382
321
|
return found;
|
|
383
322
|
}
|
|
384
|
-
|
|
385
323
|
function applyHeaderCells(tr, tableMap, state, tableStart, table, headerRowEnabled, headerColumnEnabled) {
|
|
386
324
|
const {
|
|
387
325
|
schema
|
|
388
326
|
} = state;
|
|
389
|
-
|
|
390
327
|
const setMarkup = (tr, row, col, headerEnabled) => {
|
|
391
328
|
const cellPos = tableStart + tableMap.positionAt(row, col, table);
|
|
392
329
|
const cell = tr.doc.nodeAt(cellPos);
|
|
393
330
|
const newType = headerEnabled ? schema.nodes.tableHeader : schema.nodes.tableCell;
|
|
394
331
|
const isCellTypeChanged = newType !== (cell === null || cell === void 0 ? void 0 : cell.type);
|
|
395
332
|
const isCellTypeValid = [schema.nodes.tableCell, schema.nodes.tableHeader].includes(cell === null || cell === void 0 ? void 0 : cell.type);
|
|
396
|
-
|
|
397
333
|
if (isCellTypeChanged && isCellTypeValid) {
|
|
398
334
|
tr.setNodeMarkup(cellPos, newType, cell === null || cell === void 0 ? void 0 : cell.attrs, cell === null || cell === void 0 ? void 0 : cell.marks);
|
|
399
335
|
}
|
|
400
|
-
};
|
|
401
|
-
|
|
336
|
+
};
|
|
402
337
|
|
|
403
|
-
|
|
338
|
+
// For row === 0 && col === 0 it is enabled if either are enabled
|
|
339
|
+
setMarkup(tr, 0, 0, headerColumnEnabled || headerRowEnabled);
|
|
404
340
|
|
|
341
|
+
// Header Column
|
|
405
342
|
for (let col = 1; col < tableMap.width; col++) {
|
|
406
343
|
setMarkup(tr, 0, col, headerRowEnabled);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
344
|
+
}
|
|
345
|
+
// Header Row
|
|
410
346
|
for (let row = 1; row < tableMap.height; row++) {
|
|
411
347
|
setMarkup(tr, row, 0, headerColumnEnabled);
|
|
412
348
|
}
|
|
413
|
-
}
|
|
414
|
-
// table, at the position pointed at by rect.
|
|
415
|
-
|
|
349
|
+
}
|
|
416
350
|
|
|
351
|
+
// Insert the given set of cells (as returned by `pastedCells`) into a
|
|
352
|
+
// table, at the position pointed at by rect.
|
|
417
353
|
export function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
418
354
|
let table = state.doc;
|
|
419
355
|
const newRect = selectedRect(state);
|
|
420
|
-
const types = tableNodeTypes(state.schema);
|
|
356
|
+
const types = tableNodeTypes(state.schema);
|
|
421
357
|
|
|
358
|
+
// Get if the header row and column are enabled on the original table
|
|
422
359
|
const headerRowEnabled = isHeaderEnabledByType('row', newRect, types);
|
|
423
360
|
const headerColumnEnabled = isHeaderEnabledByType('column', newRect, types);
|
|
424
|
-
|
|
425
361
|
if (tableStart) {
|
|
426
362
|
table = state.doc.nodeAt(tableStart - 1);
|
|
427
|
-
|
|
428
363
|
if (!table) {
|
|
429
364
|
throw new Error(`insertCells: could not find table at pos ${tableStart - 1}`);
|
|
430
365
|
}
|
|
431
366
|
}
|
|
432
|
-
|
|
433
367
|
let map = TableMap.get(table);
|
|
434
368
|
const {
|
|
435
369
|
top,
|
|
@@ -441,43 +375,35 @@ export function insertCells(state, dispatch, tableStart, rect, cells) {
|
|
|
441
375
|
tr
|
|
442
376
|
} = state;
|
|
443
377
|
let mapFrom = 0;
|
|
444
|
-
|
|
445
378
|
function recomp() {
|
|
446
379
|
table = tableStart ? tr.doc.nodeAt(tableStart - 1) : tr.doc;
|
|
447
380
|
map = TableMap.get(table);
|
|
448
381
|
mapFrom = tr.mapping.maps.length;
|
|
449
|
-
}
|
|
382
|
+
}
|
|
383
|
+
// Prepare the table to be large enough and not have any cells
|
|
450
384
|
// crossing the boundaries of the rectangle that we want to
|
|
451
385
|
// insert into. If anything about it changes, recompute the table
|
|
452
386
|
// map so that subsequent operations can see the current shape.
|
|
453
|
-
|
|
454
|
-
|
|
455
387
|
if (growTable(tr, map, table, tableStart, right, bottom, mapFrom)) {
|
|
456
388
|
recomp();
|
|
457
389
|
}
|
|
458
|
-
|
|
459
390
|
if (isolateHorizontal(tr, map, table, tableStart, left, right, top, mapFrom)) {
|
|
460
391
|
recomp();
|
|
461
392
|
}
|
|
462
|
-
|
|
463
393
|
if (isolateHorizontal(tr, map, table, tableStart, left, right, bottom, mapFrom)) {
|
|
464
394
|
recomp();
|
|
465
395
|
}
|
|
466
|
-
|
|
467
396
|
if (isolateVertical(tr, map, table, tableStart, top, bottom, left, mapFrom)) {
|
|
468
397
|
recomp();
|
|
469
398
|
}
|
|
470
|
-
|
|
471
399
|
if (isolateVertical(tr, map, table, tableStart, top, bottom, right, mapFrom)) {
|
|
472
400
|
recomp();
|
|
473
401
|
}
|
|
474
|
-
|
|
475
402
|
for (let row = top; row < bottom; row++) {
|
|
476
403
|
const from = map.positionAt(row, left, table);
|
|
477
404
|
const to = map.positionAt(row, right, table);
|
|
478
405
|
tr.replace(tr.mapping.slice(mapFrom).map(from + tableStart), tr.mapping.slice(mapFrom).map(to + tableStart), new Slice(cells.rows[row - top], 0, 0));
|
|
479
406
|
}
|
|
480
|
-
|
|
481
407
|
recomp();
|
|
482
408
|
applyHeaderCells(tr, map, state, tableStart, table, headerRowEnabled, headerColumnEnabled);
|
|
483
409
|
tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + map.positionAt(top, left, table)), tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table))));
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { tableNodeTypes } from './table-node-types';
|
|
2
2
|
import { uuid } from './uuid';
|
|
3
|
-
|
|
4
3
|
const createCell = (cellType, cellContent) => {
|
|
5
4
|
if (cellContent) {
|
|
6
5
|
return cellType.createChecked(null, cellContent);
|
|
7
6
|
}
|
|
8
|
-
|
|
9
7
|
return cellType.createAndFill();
|
|
10
|
-
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// Returns a table node of a given size.
|
|
11
11
|
// `withHeaderRow` defines whether the first row of the table will be a header row.
|
|
12
12
|
// `cellContent` defines the content of each cell.
|
|
13
|
-
|
|
14
|
-
|
|
15
13
|
export const createTable = ({
|
|
16
14
|
schema,
|
|
17
15
|
rowsCount = 3,
|
|
@@ -27,29 +25,22 @@ export const createTable = ({
|
|
|
27
25
|
} = tableNodeTypes(schema);
|
|
28
26
|
const cells = [];
|
|
29
27
|
const headerCells = [];
|
|
30
|
-
|
|
31
28
|
for (let i = 0; i < colsCount; i++) {
|
|
32
29
|
const cell = createCell(tableCell, cellContent);
|
|
33
|
-
|
|
34
30
|
if (cell) {
|
|
35
31
|
cells.push(cell);
|
|
36
32
|
}
|
|
37
|
-
|
|
38
33
|
if (withHeaderRow) {
|
|
39
34
|
const headerCell = createCell(tableHeader, cellContent);
|
|
40
|
-
|
|
41
35
|
if (headerCell) {
|
|
42
36
|
headerCells.push(headerCell);
|
|
43
37
|
}
|
|
44
38
|
}
|
|
45
39
|
}
|
|
46
|
-
|
|
47
40
|
const rows = [];
|
|
48
|
-
|
|
49
41
|
for (let i = 0; i < rowsCount; i++) {
|
|
50
42
|
rows.push(tableRow.createChecked(null, withHeaderRow && i === 0 ? headerCells : cells));
|
|
51
43
|
}
|
|
52
|
-
|
|
53
44
|
return table.createChecked({
|
|
54
45
|
localId: uuid.generate()
|
|
55
46
|
}, rows);
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { cloneTr } from './clone-tr';
|
|
2
|
-
import { tableNodeTypes } from './table-node-types';
|
|
2
|
+
import { tableNodeTypes } from './table-node-types';
|
|
3
3
|
|
|
4
|
+
// Returns a new transaction that clears the content of a given `cell`.
|
|
4
5
|
export const emptyCell = (cell, schema) => tr => {
|
|
5
6
|
if (cell) {
|
|
6
7
|
const node = tableNodeTypes(schema).cell.createAndFill();
|
|
7
|
-
|
|
8
8
|
if (node && !cell.node.content.eq(node.content)) {
|
|
9
9
|
tr.replaceWith(cell.pos + 1, cell.pos + cell.node.nodeSize, node.content);
|
|
10
10
|
return cloneTr(tr);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
|
|
14
13
|
return tr;
|
|
15
14
|
};
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { findParentNode, findParentNodeClosestToPos } from 'prosemirror-utils';
|
|
2
|
-
import { TableMap } from '../table-map';
|
|
2
|
+
import { TableMap } from '../table-map';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// Iterates over parent nodes, returning the closest table node.
|
|
5
|
+
export const findTable = selection => findParentNode(node => node.type.spec.tableRole && node.type.spec.tableRole === 'table')(selection);
|
|
5
6
|
|
|
7
|
+
// Iterates over parent nodes, returning a table node closest to a given `$pos`.
|
|
6
8
|
export const findTableClosestToPos = $pos => {
|
|
7
9
|
const predicate = node => node.type.spec.tableRole && node.type.spec.tableRole === 'table';
|
|
8
|
-
|
|
9
10
|
return findParentNodeClosestToPos($pos, predicate);
|
|
10
|
-
};
|
|
11
|
+
};
|
|
11
12
|
|
|
13
|
+
// Iterates over parent nodes, returning a table cell or a table header node closest to a given `$pos`.
|
|
12
14
|
export const findCellClosestToPos = $pos => {
|
|
13
15
|
const predicate = node => node.type.spec.tableRole && /cell/i.test(node.type.spec.tableRole);
|
|
14
|
-
|
|
15
16
|
return findParentNodeClosestToPos($pos, predicate);
|
|
16
|
-
};
|
|
17
|
+
};
|
|
17
18
|
|
|
19
|
+
// Returns the rectangle spanning a cell closest to a given `$pos`.
|
|
18
20
|
export const findCellRectClosestToPos = $pos => {
|
|
19
21
|
const cell = findCellClosestToPos($pos);
|
|
20
|
-
|
|
21
22
|
if (cell) {
|
|
22
23
|
const table = findTableClosestToPos($pos);
|
|
23
|
-
|
|
24
24
|
if (table) {
|
|
25
25
|
const map = TableMap.get(table.node);
|
|
26
26
|
const cellPos = cell.pos - table.start;
|