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