@lexical/table 0.1.14 → 0.1.17
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/LICENSE +1 -1
- package/LexicalTable.d.ts +237 -0
- package/LexicalTable.dev.js +993 -512
- package/LexicalTable.js.flow +246 -0
- package/LexicalTable.prod.js +42 -27
- package/package.json +5 -6
package/LexicalTable.dev.js
CHANGED
@@ -7,48 +7,51 @@
|
|
7
7
|
'use strict';
|
8
8
|
|
9
9
|
var lexical = require('lexical');
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
function addClassNamesToElement(element, ...classNames) {
|
20
|
-
classNames.forEach(className => {
|
21
|
-
if (className != null && typeof className === 'string') {
|
22
|
-
element.classList.add(...className.split(' '));
|
23
|
-
}
|
24
|
-
});
|
25
|
-
}
|
26
|
-
|
27
|
-
/**
|
28
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
29
|
-
*
|
30
|
-
* This source code is licensed under the MIT license found in the
|
31
|
-
* LICENSE file in the root directory of this source tree.
|
32
|
-
*
|
33
|
-
*
|
34
|
-
*/
|
10
|
+
var utils = require('@lexical/utils');
|
11
|
+
|
12
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
13
|
+
const TableCellHeaderStates = {
|
14
|
+
NO_STATUS: 0,
|
15
|
+
ROW: 1,
|
16
|
+
COLUMN: 2,
|
17
|
+
BOTH: 3
|
18
|
+
};
|
35
19
|
class TableCellNode extends lexical.GridCellNode {
|
36
20
|
static getType() {
|
37
21
|
return 'tablecell';
|
38
22
|
}
|
39
23
|
|
40
24
|
static clone(node) {
|
41
|
-
return new TableCellNode(
|
25
|
+
return new TableCellNode(node.__headerState, node.__colSpan, node.__width, node.__key);
|
42
26
|
}
|
43
27
|
|
44
|
-
|
28
|
+
static convertDOM() {
|
29
|
+
return {
|
30
|
+
td: node => ({
|
31
|
+
conversion: convertTableCellNodeElement,
|
32
|
+
priority: 0
|
33
|
+
}),
|
34
|
+
th: node => ({
|
35
|
+
conversion: convertTableCellNodeElement,
|
36
|
+
priority: 0
|
37
|
+
})
|
38
|
+
};
|
39
|
+
}
|
40
|
+
|
41
|
+
constructor(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width, key) {
|
45
42
|
super(colSpan, key);
|
46
|
-
this.
|
43
|
+
this.__headerState = headerState;
|
44
|
+
this.__width = width;
|
47
45
|
}
|
48
46
|
|
49
47
|
createDOM(config) {
|
50
48
|
const element = document.createElement(this.getTag());
|
51
|
-
|
49
|
+
|
50
|
+
if (this.__width) {
|
51
|
+
element.style.width = `${this.__width}px`;
|
52
|
+
}
|
53
|
+
|
54
|
+
utils.addClassNamesToElement(element, config.theme.tableCell, this.hasHeader() && config.theme.tableCellHeader);
|
52
55
|
return element;
|
53
56
|
}
|
54
57
|
|
@@ -56,38 +59,49 @@ class TableCellNode extends lexical.GridCellNode {
|
|
56
59
|
return this.hasHeader() ? 'th' : 'td';
|
57
60
|
}
|
58
61
|
|
59
|
-
setHeaderStyles(
|
62
|
+
setHeaderStyles(headerState) {
|
60
63
|
const self = this.getWritable();
|
61
|
-
self.
|
62
|
-
return this.
|
64
|
+
self.__headerState = headerState;
|
65
|
+
return this.__headerState;
|
63
66
|
}
|
64
67
|
|
65
68
|
getHeaderStyles() {
|
66
|
-
return this.getLatest().
|
69
|
+
return this.getLatest().__headerState;
|
70
|
+
}
|
71
|
+
|
72
|
+
setWidth(width) {
|
73
|
+
const self = this.getWritable();
|
74
|
+
self.__width = width;
|
75
|
+
return this.__width;
|
76
|
+
}
|
77
|
+
|
78
|
+
getWidth() {
|
79
|
+
return this.getLatest().__width;
|
67
80
|
}
|
68
81
|
|
69
|
-
toggleHeaderStyle(
|
82
|
+
toggleHeaderStyle(headerStateToToggle) {
|
70
83
|
const self = this.getWritable();
|
71
|
-
const newHeaderValue = self.getHeaderStyles();
|
72
84
|
|
73
|
-
if (
|
74
|
-
|
85
|
+
if ((self.__headerState & headerStateToToggle) === headerStateToToggle) {
|
86
|
+
self.__headerState -= headerStateToToggle;
|
75
87
|
} else {
|
76
|
-
|
88
|
+
self.__headerState += headerStateToToggle;
|
77
89
|
}
|
78
90
|
|
79
|
-
self.
|
91
|
+
self.__headerState = self.__headerState;
|
80
92
|
return self;
|
81
93
|
}
|
82
94
|
|
83
|
-
|
84
|
-
|
95
|
+
hasHeaderState(headerState) {
|
96
|
+
return (this.getHeaderStyles() & headerState) === headerState;
|
97
|
+
}
|
85
98
|
|
86
|
-
|
99
|
+
hasHeader() {
|
100
|
+
return this.getLatest().__headerState !== TableCellHeaderStates.NO_STATUS;
|
87
101
|
}
|
88
102
|
|
89
103
|
updateDOM(prevNode) {
|
90
|
-
return prevNode.
|
104
|
+
return prevNode.__headerState !== this.__headerState || prevNode.__width !== this.__width;
|
91
105
|
}
|
92
106
|
|
93
107
|
collapseAtStart() {
|
@@ -99,8 +113,29 @@ class TableCellNode extends lexical.GridCellNode {
|
|
99
113
|
}
|
100
114
|
|
101
115
|
}
|
102
|
-
function
|
103
|
-
|
116
|
+
function convertTableCellNodeElement(domNode) {
|
117
|
+
const nodeName = domNode.nodeName.toLowerCase();
|
118
|
+
const tableCellNode = $createTableCellNode(nodeName === 'th' ? TableCellHeaderStates.ROW : TableCellHeaderStates.NO_STATUS);
|
119
|
+
return {
|
120
|
+
node: tableCellNode,
|
121
|
+
forChild: (lexicalNode, parentLexicalNode) => {
|
122
|
+
if ($isTableCellNode(parentLexicalNode) && !lexical.$isElementNode(lexicalNode)) {
|
123
|
+
const paragraphNode = lexical.$createParagraphNode();
|
124
|
+
|
125
|
+
if (lexical.$isLineBreakNode(lexicalNode) && lexicalNode.getTextContent() === '\n') {
|
126
|
+
return null;
|
127
|
+
}
|
128
|
+
|
129
|
+
paragraphNode.append(lexicalNode);
|
130
|
+
return paragraphNode;
|
131
|
+
}
|
132
|
+
|
133
|
+
return lexicalNode;
|
134
|
+
}
|
135
|
+
};
|
136
|
+
}
|
137
|
+
function $createTableCellNode(headerState, colSpan = 1, width) {
|
138
|
+
return new TableCellNode(headerState, colSpan, width);
|
104
139
|
}
|
105
140
|
function $isTableCellNode(node) {
|
106
141
|
return node instanceof TableCellNode;
|
@@ -114,18 +149,273 @@ function $isTableCellNode(node) {
|
|
114
149
|
*
|
115
150
|
*
|
116
151
|
*/
|
117
|
-
|
118
|
-
let curr = startingNode;
|
152
|
+
const getSelection = () => window.getSelection();
|
119
153
|
|
120
|
-
|
121
|
-
if (findFn(curr)) {
|
122
|
-
return curr;
|
123
|
-
}
|
154
|
+
var getDOMSelection = getSelection;
|
124
155
|
|
125
|
-
|
156
|
+
/**
|
157
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
158
|
+
*
|
159
|
+
* This source code is licensed under the MIT license found in the
|
160
|
+
* LICENSE file in the root directory of this source tree.
|
161
|
+
*
|
162
|
+
*
|
163
|
+
*/
|
164
|
+
const removeHighlightStyle = document.createElement('style');
|
165
|
+
removeHighlightStyle.appendChild(document.createTextNode('::selection{background-color: transparent}'));
|
166
|
+
class TableSelection {
|
167
|
+
constructor(editor, tableNodeKey) {
|
168
|
+
this.isHighlightingCells = false;
|
169
|
+
this.startX = -1;
|
170
|
+
this.startY = -1;
|
171
|
+
this.currentX = -1;
|
172
|
+
this.currentY = -1;
|
173
|
+
this.listenersToRemove = new Set();
|
174
|
+
this.tableNodeKey = tableNodeKey;
|
175
|
+
this.editor = editor;
|
176
|
+
this.grid = {
|
177
|
+
cells: [],
|
178
|
+
columns: 0,
|
179
|
+
rows: 0
|
180
|
+
};
|
181
|
+
this.gridSelection = null;
|
182
|
+
this.anchorCellNodeKey = null;
|
183
|
+
this.focusCellNodeKey = null;
|
184
|
+
this.anchorCell = null;
|
185
|
+
this.focusCell = null;
|
186
|
+
this.trackTableGrid();
|
187
|
+
}
|
188
|
+
|
189
|
+
getGrid() {
|
190
|
+
return this.grid;
|
191
|
+
}
|
192
|
+
|
193
|
+
removeListeners() {
|
194
|
+
Array.from(this.listenersToRemove).forEach(removeListener => removeListener());
|
195
|
+
}
|
196
|
+
|
197
|
+
trackTableGrid() {
|
198
|
+
const observer = new MutationObserver(records => {
|
199
|
+
this.editor.update(() => {
|
200
|
+
let gridNeedsRedraw = false;
|
201
|
+
|
202
|
+
for (let i = 0; i < records.length; i++) {
|
203
|
+
const record = records[i];
|
204
|
+
const target = record.target;
|
205
|
+
const nodeName = target.nodeName;
|
206
|
+
|
207
|
+
if (nodeName === 'TABLE' || nodeName === 'TR') {
|
208
|
+
gridNeedsRedraw = true;
|
209
|
+
break;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
if (!gridNeedsRedraw) {
|
214
|
+
return;
|
215
|
+
}
|
216
|
+
|
217
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
218
|
+
|
219
|
+
if (!tableElement) {
|
220
|
+
throw new Error('Expected to find TableElement in DOM');
|
221
|
+
}
|
222
|
+
|
223
|
+
this.grid = getTableGrid(tableElement);
|
224
|
+
});
|
225
|
+
});
|
226
|
+
this.editor.update(() => {
|
227
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
228
|
+
|
229
|
+
if (!tableElement) {
|
230
|
+
throw new Error('Expected to find TableElement in DOM');
|
231
|
+
}
|
232
|
+
|
233
|
+
this.grid = getTableGrid(tableElement);
|
234
|
+
observer.observe(tableElement, {
|
235
|
+
childList: true,
|
236
|
+
subtree: true
|
237
|
+
});
|
238
|
+
});
|
239
|
+
}
|
240
|
+
|
241
|
+
clearHighlight() {
|
242
|
+
this.editor.update(() => {
|
243
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
244
|
+
|
245
|
+
if (!$isTableNode(tableNode)) {
|
246
|
+
throw new Error('Expected TableNode.');
|
247
|
+
}
|
248
|
+
|
249
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
250
|
+
|
251
|
+
if (!tableElement) {
|
252
|
+
throw new Error('Expected to find TableElement in DOM');
|
253
|
+
}
|
254
|
+
|
255
|
+
const grid = getTableGrid(tableElement);
|
256
|
+
this.isHighlightingCells = false;
|
257
|
+
this.startX = -1;
|
258
|
+
this.startY = -1;
|
259
|
+
this.currentX = -1;
|
260
|
+
this.currentY = -1;
|
261
|
+
this.gridSelection = null;
|
262
|
+
this.anchorCellNodeKey = null;
|
263
|
+
this.focusCellNodeKey = null;
|
264
|
+
this.anchorCell = null;
|
265
|
+
this.focusCell = null;
|
266
|
+
$updateDOMForSelection(grid, null);
|
267
|
+
lexical.$setSelection(null);
|
268
|
+
this.editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND);
|
269
|
+
const parent = removeHighlightStyle.parentNode;
|
270
|
+
|
271
|
+
if (parent != null) {
|
272
|
+
parent.removeChild(removeHighlightStyle);
|
273
|
+
}
|
274
|
+
});
|
275
|
+
}
|
276
|
+
|
277
|
+
adjustFocusCellForSelection(cell, ignoreStart = false) {
|
278
|
+
this.editor.update(() => {
|
279
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
280
|
+
|
281
|
+
if (!$isTableNode(tableNode)) {
|
282
|
+
throw new Error('Expected TableNode.');
|
283
|
+
}
|
284
|
+
|
285
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
286
|
+
|
287
|
+
if (!tableElement) {
|
288
|
+
throw new Error('Expected to find TableElement in DOM');
|
289
|
+
}
|
290
|
+
|
291
|
+
const cellX = cell.x;
|
292
|
+
const cellY = cell.y;
|
293
|
+
this.focusCell = cell;
|
294
|
+
const domSelection = getDOMSelection();
|
295
|
+
|
296
|
+
if (this.anchorCell !== null) {
|
297
|
+
// Collapse the selection
|
298
|
+
domSelection.setBaseAndExtent(this.anchorCell.elem, 0, cell.elem, 0);
|
299
|
+
}
|
300
|
+
|
301
|
+
if (!this.isHighlightingCells && (this.startX !== cellX || this.startY !== cellY || ignoreStart)) {
|
302
|
+
this.isHighlightingCells = true;
|
303
|
+
|
304
|
+
if (document.body) {
|
305
|
+
document.body.appendChild(removeHighlightStyle);
|
306
|
+
}
|
307
|
+
} else if (cellX === this.currentX && cellY === this.currentY) {
|
308
|
+
return;
|
309
|
+
}
|
310
|
+
|
311
|
+
this.currentX = cellX;
|
312
|
+
this.currentY = cellY;
|
313
|
+
|
314
|
+
if (this.isHighlightingCells) {
|
315
|
+
const focusTableCellNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
316
|
+
|
317
|
+
if (this.gridSelection != null && this.anchorCellNodeKey != null && $isTableCellNode(focusTableCellNode)) {
|
318
|
+
const focusNodeKey = focusTableCellNode.getKey();
|
319
|
+
this.gridSelection = lexical.$createGridSelection();
|
320
|
+
this.focusCellNodeKey = focusNodeKey;
|
321
|
+
this.gridSelection.set(this.tableNodeKey, // $FlowFixMe This is not null, as you can see in the statement above.
|
322
|
+
this.anchorCellNodeKey, this.focusCellNodeKey);
|
323
|
+
lexical.$setSelection(this.gridSelection);
|
324
|
+
this.editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND);
|
325
|
+
$updateDOMForSelection(this.grid, this.gridSelection);
|
326
|
+
}
|
327
|
+
}
|
328
|
+
});
|
329
|
+
}
|
330
|
+
|
331
|
+
setAnchorCellForSelection(cell) {
|
332
|
+
this.editor.update(() => {
|
333
|
+
this.anchorCell = cell;
|
334
|
+
this.startX = cell.x;
|
335
|
+
this.startY = cell.y;
|
336
|
+
const domSelection = getDOMSelection();
|
337
|
+
domSelection.setBaseAndExtent(cell.elem, 0, cell.elem, 0);
|
338
|
+
const anchorTableCellNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
339
|
+
|
340
|
+
if ($isTableCellNode(anchorTableCellNode)) {
|
341
|
+
const anchorNodeKey = anchorTableCellNode.getKey();
|
342
|
+
this.gridSelection = lexical.$createGridSelection();
|
343
|
+
this.anchorCellNodeKey = anchorNodeKey;
|
344
|
+
}
|
345
|
+
});
|
346
|
+
}
|
347
|
+
|
348
|
+
formatCells(type) {
|
349
|
+
this.editor.update(() => {
|
350
|
+
const selection = lexical.$getSelection();
|
351
|
+
|
352
|
+
if (!lexical.$isGridSelection(selection)) {
|
353
|
+
{
|
354
|
+
throw Error(`Expected grid selection`);
|
355
|
+
}
|
356
|
+
} // This is to make Flow play ball.
|
357
|
+
|
358
|
+
|
359
|
+
const formatSelection = lexical.$createRangeSelection();
|
360
|
+
const anchor = formatSelection.anchor;
|
361
|
+
const focus = formatSelection.focus;
|
362
|
+
selection.getNodes().forEach(cellNode => {
|
363
|
+
if ($isTableCellNode(cellNode) && cellNode.getTextContentSize() !== 0) {
|
364
|
+
anchor.set(cellNode.getKey(), 0, 'element');
|
365
|
+
focus.set(cellNode.getKey(), cellNode.getChildrenSize(), 'element');
|
366
|
+
formatSelection.formatText(type);
|
367
|
+
}
|
368
|
+
});
|
369
|
+
lexical.$setSelection(selection);
|
370
|
+
this.editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND);
|
371
|
+
});
|
372
|
+
}
|
373
|
+
|
374
|
+
clearText() {
|
375
|
+
this.editor.update(() => {
|
376
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
377
|
+
|
378
|
+
if (!$isTableNode(tableNode)) {
|
379
|
+
throw new Error('Expected TableNode.');
|
380
|
+
}
|
381
|
+
|
382
|
+
const selection = lexical.$getSelection();
|
383
|
+
|
384
|
+
if (!lexical.$isGridSelection(selection)) {
|
385
|
+
{
|
386
|
+
throw Error(`Expected grid selection`);
|
387
|
+
}
|
388
|
+
}
|
389
|
+
|
390
|
+
const selectedNodes = selection.getNodes().filter($isTableCellNode);
|
391
|
+
|
392
|
+
if (selectedNodes.length === this.grid.columns * this.grid.rows) {
|
393
|
+
tableNode.selectPrevious(); // Delete entire table
|
394
|
+
|
395
|
+
tableNode.remove();
|
396
|
+
this.clearHighlight();
|
397
|
+
return;
|
398
|
+
}
|
399
|
+
|
400
|
+
selectedNodes.forEach(cellNode => {
|
401
|
+
if (lexical.$isElementNode(cellNode)) {
|
402
|
+
const paragraphNode = lexical.$createParagraphNode();
|
403
|
+
const textNode = lexical.$createTextNode();
|
404
|
+
paragraphNode.append(textNode);
|
405
|
+
cellNode.append(paragraphNode);
|
406
|
+
cellNode.getChildren().forEach(child => {
|
407
|
+
if (child !== paragraphNode) {
|
408
|
+
child.remove();
|
409
|
+
}
|
410
|
+
});
|
411
|
+
}
|
412
|
+
});
|
413
|
+
$updateDOMForSelection(this.grid, null);
|
414
|
+
lexical.$setSelection(null);
|
415
|
+
this.editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND);
|
416
|
+
});
|
126
417
|
}
|
127
418
|
|
128
|
-
return null;
|
129
419
|
}
|
130
420
|
|
131
421
|
/**
|
@@ -136,22 +426,404 @@ function $findMatchingParent(startingNode, findFn) {
|
|
136
426
|
*
|
137
427
|
*
|
138
428
|
*/
|
139
|
-
const
|
429
|
+
const CriticalPriority = 4;
|
430
|
+
const LEXICAL_ELEMENT_KEY = '__lexicalTableSelection';
|
431
|
+
function applyTableHandlers(tableNode, tableElement, editor) {
|
432
|
+
const rootElement = editor.getRootElement();
|
433
|
+
|
434
|
+
if (rootElement === null) {
|
435
|
+
throw new Error('No root element.');
|
436
|
+
}
|
437
|
+
|
438
|
+
const tableSelection = new TableSelection(editor, tableNode.getKey());
|
439
|
+
attachTableSelectionToTableElement(tableElement, tableSelection);
|
440
|
+
let isMouseDown = false;
|
441
|
+
tableElement.addEventListener('dblclick', event => {
|
442
|
+
// $FlowFixMe: event.target is always a Node on the DOM
|
443
|
+
const cell = getCellFromTarget(event.target);
|
444
|
+
|
445
|
+
if (cell !== null) {
|
446
|
+
event.preventDefault();
|
447
|
+
event.stopImmediatePropagation();
|
448
|
+
event.stopPropagation();
|
449
|
+
tableSelection.setAnchorCellForSelection(cell);
|
450
|
+
tableSelection.adjustFocusCellForSelection(cell, true);
|
451
|
+
isMouseDown = false;
|
452
|
+
}
|
453
|
+
}); // This is the anchor of the selection.
|
454
|
+
|
455
|
+
tableElement.addEventListener('mousedown', event => {
|
456
|
+
setTimeout(() => {
|
457
|
+
if (event.button !== 0) {
|
458
|
+
return;
|
459
|
+
} // $FlowFixMe: event.target is always a Node on the DOM
|
460
|
+
|
461
|
+
|
462
|
+
const cell = getCellFromTarget(event.target);
|
463
|
+
|
464
|
+
if (cell !== null) {
|
465
|
+
isMouseDown = true;
|
466
|
+
tableSelection.setAnchorCellForSelection(cell);
|
467
|
+
document.addEventListener('mouseup', () => {
|
468
|
+
isMouseDown = false;
|
469
|
+
}, {
|
470
|
+
capture: true,
|
471
|
+
once: true
|
472
|
+
});
|
473
|
+
}
|
474
|
+
}, 0);
|
475
|
+
}); // This is adjusting the focus of the selection.
|
476
|
+
|
477
|
+
tableElement.addEventListener('mousemove', event => {
|
478
|
+
if (isMouseDown) {
|
479
|
+
// $FlowFixMe: event.target is always a Node on the DOM
|
480
|
+
const cell = getCellFromTarget(event.target);
|
481
|
+
|
482
|
+
if (cell !== null) {
|
483
|
+
const cellX = cell.x;
|
484
|
+
const cellY = cell.y;
|
485
|
+
|
486
|
+
if (isMouseDown && (tableSelection.startX !== cellX || tableSelection.startY !== cellY || tableSelection.isHighlightingCells)) {
|
487
|
+
event.preventDefault();
|
488
|
+
isMouseDown = true;
|
489
|
+
tableSelection.adjustFocusCellForSelection(cell);
|
490
|
+
}
|
491
|
+
}
|
492
|
+
}
|
493
|
+
});
|
494
|
+
tableElement.addEventListener('mouseup', event => {
|
495
|
+
if (isMouseDown) {
|
496
|
+
isMouseDown = false;
|
497
|
+
}
|
498
|
+
}); // Select entire table at this point, when grid selection is ready.
|
499
|
+
|
500
|
+
tableElement.addEventListener('mouseleave', event => {
|
501
|
+
if (isMouseDown) {
|
502
|
+
return;
|
503
|
+
}
|
504
|
+
}); // Clear selection when clicking outside of dom.
|
505
|
+
|
506
|
+
const mouseDownCallback = event => {
|
507
|
+
if (event.button !== 0) {
|
508
|
+
return;
|
509
|
+
}
|
510
|
+
|
511
|
+
editor.update(() => {
|
512
|
+
const selection = lexical.$getSelection();
|
513
|
+
|
514
|
+
if (lexical.$isGridSelection(selection) && selection.gridKey === tableSelection.tableNodeKey && rootElement.contains(event.target)) {
|
515
|
+
return tableSelection.clearHighlight();
|
516
|
+
}
|
517
|
+
});
|
518
|
+
};
|
519
|
+
|
520
|
+
window.addEventListener('mousedown', mouseDownCallback);
|
521
|
+
tableSelection.listenersToRemove.add(() => window.removeEventListener('mousedown', mouseDownCallback));
|
522
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_DOWN_COMMAND, payload => {
|
523
|
+
const selection = lexical.$getSelection();
|
524
|
+
const event = payload;
|
525
|
+
const direction = 'down';
|
526
|
+
|
527
|
+
if (lexical.$isRangeSelection(selection)) {
|
528
|
+
if (selection.isCollapsed()) {
|
529
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
530
|
+
|
531
|
+
if (!$isTableCellNode(tableCellNode)) {
|
532
|
+
return false;
|
533
|
+
}
|
534
|
+
|
535
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
536
|
+
const elementParentNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
537
|
+
|
538
|
+
if (elementParentNode == null) {
|
539
|
+
throw new Error('Expected BlockNode Parent');
|
540
|
+
}
|
541
|
+
|
542
|
+
const lastChild = tableCellNode.getLastChild();
|
543
|
+
const isSelectionInLastBlock = lastChild && elementParentNode.isParentOf(lastChild) || elementParentNode === lastChild;
|
544
|
+
|
545
|
+
if (isSelectionInLastBlock || event.shiftKey) {
|
546
|
+
event.preventDefault();
|
547
|
+
event.stopImmediatePropagation();
|
548
|
+
event.stopPropagation(); // Start Selection
|
549
|
+
|
550
|
+
if (event.shiftKey) {
|
551
|
+
tableSelection.setAnchorCellForSelection(tableNode.getCellFromCordsOrThrow(currentCords.x, currentCords.y, tableSelection.grid));
|
552
|
+
return adjustFocusNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
553
|
+
}
|
554
|
+
|
555
|
+
return selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
556
|
+
}
|
557
|
+
}
|
558
|
+
} else if (lexical.$isGridSelection(selection) && event.shiftKey) {
|
559
|
+
const tableCellNode = selection.focus.getNode();
|
560
|
+
|
561
|
+
if (!$isTableCellNode(tableCellNode)) {
|
562
|
+
return false;
|
563
|
+
}
|
564
|
+
|
565
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
566
|
+
event.preventDefault();
|
567
|
+
event.stopImmediatePropagation();
|
568
|
+
event.stopPropagation();
|
569
|
+
return adjustFocusNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
570
|
+
}
|
571
|
+
|
572
|
+
return false;
|
573
|
+
}, CriticalPriority));
|
574
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, payload => {
|
575
|
+
const selection = lexical.$getSelection();
|
576
|
+
const event = payload;
|
577
|
+
const direction = 'up';
|
578
|
+
|
579
|
+
if (lexical.$isRangeSelection(selection)) {
|
580
|
+
if (selection.isCollapsed()) {
|
581
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
582
|
+
|
583
|
+
if (!$isTableCellNode(tableCellNode)) {
|
584
|
+
return false;
|
585
|
+
}
|
586
|
+
|
587
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
588
|
+
const elementParentNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
589
|
+
|
590
|
+
if (elementParentNode == null) {
|
591
|
+
throw new Error('Expected BlockNode Parent');
|
592
|
+
}
|
593
|
+
|
594
|
+
const lastChild = tableCellNode.getLastChild();
|
595
|
+
const isSelectionInLastBlock = lastChild && elementParentNode.isParentOf(lastChild) || elementParentNode === lastChild;
|
596
|
+
|
597
|
+
if (isSelectionInLastBlock || event.shiftKey) {
|
598
|
+
event.preventDefault();
|
599
|
+
event.stopImmediatePropagation();
|
600
|
+
event.stopPropagation(); // Start Selection
|
601
|
+
|
602
|
+
if (event.shiftKey) {
|
603
|
+
tableSelection.setAnchorCellForSelection(tableNode.getCellFromCordsOrThrow(currentCords.x, currentCords.y, tableSelection.grid));
|
604
|
+
return adjustFocusNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
605
|
+
}
|
606
|
+
|
607
|
+
return selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
608
|
+
}
|
609
|
+
}
|
610
|
+
} else if (lexical.$isGridSelection(selection) && event.shiftKey) {
|
611
|
+
const tableCellNode = selection.focus.getNode();
|
612
|
+
|
613
|
+
if (!$isTableCellNode(tableCellNode)) {
|
614
|
+
return false;
|
615
|
+
}
|
616
|
+
|
617
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
618
|
+
event.preventDefault();
|
619
|
+
event.stopImmediatePropagation();
|
620
|
+
event.stopPropagation();
|
621
|
+
return adjustFocusNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
622
|
+
}
|
623
|
+
|
624
|
+
return false;
|
625
|
+
}, CriticalPriority));
|
626
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_LEFT_COMMAND, payload => {
|
627
|
+
const selection = lexical.$getSelection();
|
628
|
+
const event = payload;
|
629
|
+
const direction = 'backward';
|
630
|
+
|
631
|
+
if (lexical.$isRangeSelection(selection)) {
|
632
|
+
if (selection.isCollapsed()) {
|
633
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
634
|
+
|
635
|
+
if (!$isTableCellNode(tableCellNode)) {
|
636
|
+
return false;
|
637
|
+
}
|
638
|
+
|
639
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
640
|
+
const elementParentNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
641
|
+
|
642
|
+
if (elementParentNode == null) {
|
643
|
+
throw new Error('Expected BlockNode Parent');
|
644
|
+
}
|
645
|
+
|
646
|
+
if (selection.anchor.offset === 0 || event.shiftKey) {
|
647
|
+
event.preventDefault();
|
648
|
+
event.stopImmediatePropagation();
|
649
|
+
event.stopPropagation(); // Start Selection
|
650
|
+
|
651
|
+
if (event.shiftKey) {
|
652
|
+
tableSelection.setAnchorCellForSelection(tableNode.getCellFromCordsOrThrow(currentCords.x, currentCords.y, tableSelection.grid));
|
653
|
+
return adjustFocusNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
654
|
+
}
|
655
|
+
|
656
|
+
return selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
657
|
+
}
|
658
|
+
}
|
659
|
+
} else if (lexical.$isGridSelection(selection) && event.shiftKey) {
|
660
|
+
const tableCellNode = selection.focus.getNode();
|
661
|
+
|
662
|
+
if (!$isTableCellNode(tableCellNode)) {
|
663
|
+
return false;
|
664
|
+
}
|
665
|
+
|
666
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
667
|
+
event.preventDefault();
|
668
|
+
event.stopImmediatePropagation();
|
669
|
+
event.stopPropagation();
|
670
|
+
return adjustFocusNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
671
|
+
}
|
672
|
+
|
673
|
+
return false;
|
674
|
+
}, CriticalPriority));
|
675
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_RIGHT_COMMAND, payload => {
|
676
|
+
const selection = lexical.$getSelection();
|
677
|
+
const event = payload;
|
678
|
+
const direction = 'forward';
|
679
|
+
|
680
|
+
if (lexical.$isRangeSelection(selection)) {
|
681
|
+
if (selection.isCollapsed()) {
|
682
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
683
|
+
|
684
|
+
if (!$isTableCellNode(tableCellNode)) {
|
685
|
+
return false;
|
686
|
+
}
|
687
|
+
|
688
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
689
|
+
const elementParentNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
690
|
+
|
691
|
+
if (elementParentNode == null) {
|
692
|
+
throw new Error('Expected BlockNode Parent');
|
693
|
+
}
|
694
|
+
|
695
|
+
if (selection.anchor.offset === selection.anchor.getNode().getTextContentSize() || event.shiftKey) {
|
696
|
+
event.preventDefault();
|
697
|
+
event.stopImmediatePropagation();
|
698
|
+
event.stopPropagation(); // Start Selection
|
699
|
+
|
700
|
+
if (event.shiftKey) {
|
701
|
+
tableSelection.setAnchorCellForSelection(tableNode.getCellFromCordsOrThrow(currentCords.x, currentCords.y, tableSelection.grid));
|
702
|
+
return adjustFocusNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
703
|
+
}
|
704
|
+
|
705
|
+
return selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
706
|
+
}
|
707
|
+
}
|
708
|
+
} else if (lexical.$isGridSelection(selection) && event.shiftKey) {
|
709
|
+
const tableCellNode = selection.focus.getNode();
|
710
|
+
|
711
|
+
if (!$isTableCellNode(tableCellNode)) {
|
712
|
+
return false;
|
713
|
+
}
|
714
|
+
|
715
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
716
|
+
event.preventDefault();
|
717
|
+
event.stopImmediatePropagation();
|
718
|
+
event.stopPropagation();
|
719
|
+
return adjustFocusNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, direction);
|
720
|
+
}
|
721
|
+
|
722
|
+
return false;
|
723
|
+
}, CriticalPriority));
|
724
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.DELETE_CHARACTER_COMMAND, () => {
|
725
|
+
const selection = lexical.$getSelection();
|
726
|
+
|
727
|
+
if (lexical.$isGridSelection(selection)) {
|
728
|
+
tableSelection.clearText();
|
729
|
+
return true;
|
730
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
731
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
732
|
+
|
733
|
+
if (!$isTableCellNode(tableCellNode)) {
|
734
|
+
return false;
|
735
|
+
}
|
736
|
+
|
737
|
+
if (selection.isCollapsed() && selection.anchor.offset === 0 && selection.anchor.getNode().getPreviousSiblings().length === 0) {
|
738
|
+
return true;
|
739
|
+
}
|
740
|
+
}
|
741
|
+
|
742
|
+
return false;
|
743
|
+
}, CriticalPriority));
|
744
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_BACKSPACE_COMMAND, payload => {
|
745
|
+
const selection = lexical.$getSelection();
|
746
|
+
|
747
|
+
if (lexical.$isGridSelection(selection)) {
|
748
|
+
const event = payload;
|
749
|
+
event.preventDefault();
|
750
|
+
event.stopPropagation();
|
751
|
+
tableSelection.clearText();
|
752
|
+
return true;
|
753
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
754
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
755
|
+
|
756
|
+
if (!$isTableCellNode(tableCellNode)) {
|
757
|
+
return false;
|
758
|
+
}
|
759
|
+
}
|
760
|
+
|
761
|
+
return false;
|
762
|
+
}, CriticalPriority));
|
763
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.FORMAT_TEXT_COMMAND, payload => {
|
764
|
+
const selection = lexical.$getSelection();
|
765
|
+
|
766
|
+
if (lexical.$isGridSelection(selection)) {
|
767
|
+
tableSelection.formatCells(payload);
|
768
|
+
return true;
|
769
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
770
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
771
|
+
|
772
|
+
if (!$isTableCellNode(tableCellNode)) {
|
773
|
+
return false;
|
774
|
+
}
|
775
|
+
}
|
776
|
+
|
777
|
+
return false;
|
778
|
+
}, CriticalPriority));
|
779
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.INSERT_TEXT_COMMAND, payload => {
|
780
|
+
const selection = lexical.$getSelection();
|
781
|
+
|
782
|
+
if (lexical.$isGridSelection(selection)) {
|
783
|
+
tableSelection.clearHighlight();
|
784
|
+
return false;
|
785
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
786
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
787
|
+
|
788
|
+
if (!$isTableCellNode(tableCellNode)) {
|
789
|
+
return false;
|
790
|
+
}
|
791
|
+
}
|
792
|
+
|
793
|
+
return false;
|
794
|
+
}, CriticalPriority));
|
795
|
+
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_TAB_COMMAND, payload => {
|
796
|
+
const selection = lexical.$getSelection();
|
797
|
+
|
798
|
+
if (lexical.$isRangeSelection(selection)) {
|
799
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
800
|
+
|
801
|
+
if (!$isTableCellNode(tableCellNode)) {
|
802
|
+
return false;
|
803
|
+
}
|
140
804
|
|
141
|
-
|
805
|
+
const event = payload;
|
142
806
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
807
|
+
if (selection.isCollapsed()) {
|
808
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
809
|
+
event.preventDefault();
|
810
|
+
selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, !event.shiftKey ? 'forward' : 'backward');
|
811
|
+
return true;
|
812
|
+
}
|
813
|
+
}
|
814
|
+
|
815
|
+
return false;
|
816
|
+
}, CriticalPriority));
|
817
|
+
return tableSelection;
|
818
|
+
}
|
819
|
+
function attachTableSelectionToTableElement(tableElement, tableSelection) {
|
820
|
+
// $FlowFixMe
|
821
|
+
tableElement[LEXICAL_ELEMENT_KEY] = tableSelection;
|
822
|
+
}
|
823
|
+
function getTableSelectionFromTableElement(tableElement) {
|
824
|
+
// $FlowFixMe
|
825
|
+
return tableElement[LEXICAL_ELEMENT_KEY];
|
826
|
+
}
|
155
827
|
function getCellFromTarget(node) {
|
156
828
|
let currentNode = node;
|
157
829
|
|
@@ -174,108 +846,80 @@ function getCellFromTarget(node) {
|
|
174
846
|
|
175
847
|
return null;
|
176
848
|
}
|
177
|
-
function
|
849
|
+
function getTableGrid(tableElement) {
|
178
850
|
const cells = [];
|
179
851
|
const grid = {
|
180
852
|
cells,
|
181
853
|
columns: 0,
|
182
854
|
rows: 0
|
183
855
|
};
|
856
|
+
let currentNode = tableElement.firstChild;
|
857
|
+
let x = 0;
|
858
|
+
let y = 0;
|
859
|
+
cells.length = 0;
|
184
860
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
}; // $FlowFixMe: internal field
|
203
|
-
|
204
|
-
currentNode._cell = cell;
|
205
|
-
|
206
|
-
if (cells[y] === undefined) {
|
207
|
-
cells[y] = [];
|
208
|
-
}
|
209
|
-
|
210
|
-
cells[y][x] = cell;
|
211
|
-
} else {
|
212
|
-
const child = currentNode.firstChild;
|
213
|
-
|
214
|
-
if (child != null) {
|
215
|
-
currentNode = child;
|
216
|
-
continue;
|
217
|
-
}
|
861
|
+
while (currentNode != null) {
|
862
|
+
const nodeMame = currentNode.nodeName;
|
863
|
+
|
864
|
+
if (nodeMame === 'TD' || nodeMame === 'TH') {
|
865
|
+
// $FlowFixMe: TD is always an HTMLElement
|
866
|
+
const elem = currentNode;
|
867
|
+
const cell = {
|
868
|
+
elem,
|
869
|
+
highlighted: false,
|
870
|
+
x,
|
871
|
+
y
|
872
|
+
}; // $FlowFixMe: internal field
|
873
|
+
|
874
|
+
currentNode._cell = cell;
|
875
|
+
|
876
|
+
if (cells[y] === undefined) {
|
877
|
+
cells[y] = [];
|
218
878
|
}
|
219
879
|
|
220
|
-
|
880
|
+
cells[y][x] = cell;
|
881
|
+
} else {
|
882
|
+
const child = currentNode.firstChild;
|
221
883
|
|
222
|
-
if (
|
223
|
-
|
224
|
-
currentNode = sibling;
|
884
|
+
if (child != null) {
|
885
|
+
currentNode = child;
|
225
886
|
continue;
|
226
887
|
}
|
888
|
+
}
|
227
889
|
|
228
|
-
|
229
|
-
|
230
|
-
if (parent != null) {
|
231
|
-
const parentSibling = parent.nextSibling;
|
232
|
-
|
233
|
-
if (parentSibling == null) {
|
234
|
-
break;
|
235
|
-
}
|
890
|
+
const sibling = currentNode.nextSibling;
|
236
891
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
892
|
+
if (sibling != null) {
|
893
|
+
x++;
|
894
|
+
currentNode = sibling;
|
895
|
+
continue;
|
241
896
|
}
|
242
897
|
|
243
|
-
|
244
|
-
grid.rows = y + 1;
|
245
|
-
tableNode.setGrid(grid);
|
246
|
-
};
|
247
|
-
|
248
|
-
const observer = new MutationObserver(records => {
|
249
|
-
editor.update(() => {
|
250
|
-
let gridNeedsRedraw = false;
|
898
|
+
const parent = currentNode.parentNode;
|
251
899
|
|
252
|
-
|
253
|
-
|
254
|
-
const target = record.target;
|
255
|
-
const nodeName = target.nodeName;
|
900
|
+
if (parent != null) {
|
901
|
+
const parentSibling = parent.nextSibling;
|
256
902
|
|
257
|
-
|
258
|
-
|
259
|
-
break;
|
260
|
-
}
|
903
|
+
if (parentSibling == null) {
|
904
|
+
break;
|
261
905
|
}
|
262
906
|
|
263
|
-
|
264
|
-
|
265
|
-
|
907
|
+
y++;
|
908
|
+
x = 0;
|
909
|
+
currentNode = parentSibling;
|
910
|
+
}
|
911
|
+
}
|
266
912
|
|
267
|
-
|
268
|
-
|
269
|
-
});
|
270
|
-
observer.observe(tableElement, {
|
271
|
-
childList: true,
|
272
|
-
subtree: true
|
273
|
-
});
|
274
|
-
calcSize();
|
913
|
+
grid.columns = x + 1;
|
914
|
+
grid.rows = y + 1;
|
275
915
|
return grid;
|
276
916
|
}
|
277
|
-
function
|
278
|
-
const
|
917
|
+
function $updateDOMForSelection(grid, gridSelection) {
|
918
|
+
const highlightedCells = [];
|
919
|
+
const {
|
920
|
+
cells
|
921
|
+
} = grid;
|
922
|
+
const selectedCellNodes = new Set(gridSelection ? gridSelection.getNodes() : []);
|
279
923
|
|
280
924
|
for (let y = 0; y < cells.length; y++) {
|
281
925
|
const row = cells[y];
|
@@ -283,16 +927,14 @@ function updateCells(fromX, toX, fromY, toY, cells) {
|
|
283
927
|
for (let x = 0; x < row.length; x++) {
|
284
928
|
const cell = row[x];
|
285
929
|
const elemStyle = cell.elem.style;
|
930
|
+
const lexicalNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
286
931
|
|
287
|
-
if (
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
highlighted.push(cell);
|
295
|
-
} else if (cell.highlighted) {
|
932
|
+
if (lexicalNode && selectedCellNodes.has(lexicalNode)) {
|
933
|
+
cell.highlighted = true;
|
934
|
+
elemStyle.setProperty('background-color', 'rgb(163, 187, 255)');
|
935
|
+
elemStyle.setProperty('caret-color', 'transparent');
|
936
|
+
highlightedCells.push(cell);
|
937
|
+
} else {
|
296
938
|
cell.highlighted = false;
|
297
939
|
elemStyle.removeProperty('background-color');
|
298
940
|
elemStyle.removeProperty('caret-color');
|
@@ -304,319 +946,103 @@ function updateCells(fromX, toX, fromY, toY, cells) {
|
|
304
946
|
}
|
305
947
|
}
|
306
948
|
|
307
|
-
return
|
949
|
+
return highlightedCells;
|
308
950
|
}
|
309
|
-
function $applyCustomTableHandlers(tableNode, tableElement, editor) {
|
310
|
-
const rootElement = editor.getRootElement();
|
311
|
-
|
312
|
-
if (rootElement === null) {
|
313
|
-
throw new Error('No root element.');
|
314
|
-
}
|
315
|
-
|
316
|
-
trackTableGrid(tableNode, tableElement, editor);
|
317
|
-
const grid = tableNode.getGrid();
|
318
|
-
let isSelected = false;
|
319
|
-
let isHighlightingCells = false;
|
320
|
-
let startX = -1;
|
321
|
-
let startY = -1;
|
322
|
-
let currentX = -1;
|
323
|
-
let currentY = -1;
|
324
|
-
let highlightedCells = [];
|
325
|
-
const editorListeners = new Set();
|
326
|
-
let deleteCharacterListener = null;
|
327
|
-
|
328
|
-
if (grid == null) {
|
329
|
-
throw new Error('Table grid not found.');
|
330
|
-
}
|
331
|
-
|
332
|
-
tableElement.addEventListener('mousemove', event => {
|
333
|
-
if (isSelected) {
|
334
|
-
// $FlowFixMe: event.target is always a Node on the DOM
|
335
|
-
const cell = getCellFromTarget(event.target);
|
336
|
-
|
337
|
-
if (cell !== null) {
|
338
|
-
const cellX = cell.x;
|
339
|
-
const cellY = cell.y;
|
340
|
-
|
341
|
-
if (!isHighlightingCells && (startX !== cellX || startY !== cellY)) {
|
342
|
-
event.preventDefault();
|
343
|
-
const domSelection = getDOMSelection();
|
344
|
-
const anchorNode = domSelection.anchorNode;
|
345
951
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
if (document.body) {
|
354
|
-
document.body.appendChild(removeHighlightStyle);
|
355
|
-
}
|
952
|
+
const selectGridNodeInDirection = (tableSelection, tableNode, x, y, direction) => {
|
953
|
+
switch (direction) {
|
954
|
+
case 'backward':
|
955
|
+
case 'forward':
|
956
|
+
{
|
957
|
+
const isForward = direction === 'forward';
|
356
958
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
}
|
367
|
-
|
368
|
-
highlightedCells.forEach(({
|
369
|
-
elem
|
370
|
-
}) => {
|
371
|
-
const cellNode = lexical.$getNearestNodeFromDOMNode(elem);
|
372
|
-
|
373
|
-
if (lexical.$isElementNode(cellNode)) {
|
374
|
-
const paragraphNode = lexical.$createParagraphNode();
|
375
|
-
const textNode = lexical.$createTextNode();
|
376
|
-
paragraphNode.append(textNode);
|
377
|
-
cellNode.append(paragraphNode);
|
378
|
-
cellNode.getChildren().forEach(child => {
|
379
|
-
if (child !== paragraphNode) {
|
380
|
-
child.remove();
|
381
|
-
}
|
382
|
-
});
|
383
|
-
}
|
384
|
-
});
|
385
|
-
tableNode.setSelectionState(null);
|
386
|
-
lexical.$setSelection(null);
|
387
|
-
return true;
|
388
|
-
} else if (type === 'formatText') {
|
389
|
-
formatCells(payload);
|
390
|
-
return true;
|
391
|
-
} else if (type === 'insertText') {
|
392
|
-
clearHighlight();
|
393
|
-
return false;
|
394
|
-
}
|
395
|
-
|
396
|
-
return false;
|
397
|
-
}, LowPriority);
|
398
|
-
editorListeners.add(deleteCharacterListener);
|
959
|
+
if (x !== (isForward ? tableSelection.grid.columns - 1 : 0)) {
|
960
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableSelection.grid));
|
961
|
+
} else {
|
962
|
+
if (y !== (isForward ? tableSelection.grid.rows - 1 : 0)) {
|
963
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : tableSelection.grid.columns - 1, y + (isForward ? 1 : -1), tableSelection.grid));
|
964
|
+
} else if (!isForward) {
|
965
|
+
tableNode.selectPrevious();
|
966
|
+
} else {
|
967
|
+
tableNode.selectNext();
|
399
968
|
}
|
400
|
-
} else if (cellX === currentX && cellY === currentY) {
|
401
|
-
return;
|
402
|
-
}
|
403
|
-
|
404
|
-
currentX = cellX;
|
405
|
-
currentY = cellY;
|
406
|
-
|
407
|
-
if (isHighlightingCells) {
|
408
|
-
const fromX = Math.min(startX, currentX);
|
409
|
-
const toX = Math.max(startX, currentX);
|
410
|
-
const fromY = Math.min(startY, currentY);
|
411
|
-
const toY = Math.max(startY, currentY);
|
412
|
-
editor.update(() => {
|
413
|
-
highlightedCells = tableNode.setSelectionState({
|
414
|
-
fromX,
|
415
|
-
fromY,
|
416
|
-
toX,
|
417
|
-
toY
|
418
|
-
});
|
419
|
-
});
|
420
969
|
}
|
421
|
-
}
|
422
|
-
}
|
423
|
-
});
|
424
|
-
|
425
|
-
const clearHighlight = () => {
|
426
|
-
editor.update(() => {
|
427
|
-
isHighlightingCells = false;
|
428
|
-
isSelected = false;
|
429
|
-
startX = -1;
|
430
|
-
startY = -1;
|
431
|
-
currentX = -1;
|
432
|
-
currentY = -1;
|
433
|
-
editor.update(() => {
|
434
|
-
tableNode.setSelectionState(null);
|
435
|
-
});
|
436
|
-
highlightedCells = [];
|
437
|
-
|
438
|
-
if (deleteCharacterListener !== null) {
|
439
|
-
deleteCharacterListener();
|
440
|
-
deleteCharacterListener = null;
|
441
|
-
editorListeners.delete(deleteCharacterListener);
|
442
|
-
}
|
443
|
-
|
444
|
-
const parent = removeHighlightStyle.parentNode;
|
445
|
-
|
446
|
-
if (parent != null) {
|
447
|
-
parent.removeChild(removeHighlightStyle);
|
448
|
-
}
|
449
|
-
});
|
450
|
-
};
|
451
|
-
|
452
|
-
tableElement.addEventListener('mouseleave', event => {
|
453
|
-
if (isSelected) {
|
454
|
-
return;
|
455
|
-
}
|
456
|
-
});
|
457
|
-
|
458
|
-
const formatCells = type => {
|
459
|
-
let selection = lexical.$getSelection();
|
460
|
-
|
461
|
-
if (!lexical.$isRangeSelection(selection)) {
|
462
|
-
selection = lexical.$createRangeSelection();
|
463
|
-
} // This is to make Flow play ball.
|
464
|
-
|
465
970
|
|
466
|
-
|
467
|
-
const anchor = formatSelection.anchor;
|
468
|
-
const focus = formatSelection.focus;
|
469
|
-
highlightedCells.forEach(highlightedCell => {
|
470
|
-
const cellNode = lexical.$getNearestNodeFromDOMNode(highlightedCell.elem);
|
471
|
-
|
472
|
-
if (lexical.$isElementNode(cellNode) && cellNode.getTextContentSize() !== 0) {
|
473
|
-
anchor.set(cellNode.getKey(), 0, 'element');
|
474
|
-
focus.set(cellNode.getKey(), cellNode.getChildrenSize(), 'element');
|
475
|
-
formatSelection.formatText(type);
|
971
|
+
return true;
|
476
972
|
}
|
477
|
-
}); // Collapse selection
|
478
973
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
974
|
+
case 'up':
|
975
|
+
{
|
976
|
+
if (y !== 0) {
|
977
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y - 1, tableSelection.grid));
|
978
|
+
} else {
|
979
|
+
tableNode.selectPrevious();
|
980
|
+
}
|
483
981
|
|
484
|
-
|
485
|
-
if (isSelected) {
|
486
|
-
if (isHighlightingCells) {
|
487
|
-
clearHighlight();
|
982
|
+
return true;
|
488
983
|
}
|
489
984
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
const cell = getCellFromTarget(event.target);
|
985
|
+
case 'down':
|
986
|
+
{
|
987
|
+
if (y !== tableSelection.grid.rows - 1) {
|
988
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y + 1, tableSelection.grid));
|
989
|
+
} else {
|
990
|
+
tableNode.selectNext();
|
991
|
+
}
|
500
992
|
|
501
|
-
|
502
|
-
isSelected = true;
|
503
|
-
startX = cell.x;
|
504
|
-
startY = cell.y;
|
505
|
-
document.addEventListener('mouseup', () => {
|
506
|
-
isSelected = false;
|
507
|
-
}, {
|
508
|
-
capture: true,
|
509
|
-
once: true
|
510
|
-
});
|
993
|
+
return true;
|
511
994
|
}
|
512
|
-
|
513
|
-
});
|
514
|
-
window.addEventListener('click', e => {
|
515
|
-
if (highlightedCells.length > 0 && !tableElement.contains(e.target) && rootElement.contains(e.target)) {
|
516
|
-
editor.update(() => {
|
517
|
-
tableNode.setSelectionState(null);
|
518
|
-
});
|
519
|
-
}
|
520
|
-
});
|
995
|
+
}
|
521
996
|
|
522
|
-
|
523
|
-
|
524
|
-
case 'backward':
|
525
|
-
case 'forward':
|
526
|
-
{
|
527
|
-
const isForward = direction === 'forward';
|
997
|
+
return false;
|
998
|
+
};
|
528
999
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
tableNode.selectPrevious();
|
536
|
-
} else {
|
537
|
-
tableNode.selectNext();
|
538
|
-
}
|
539
|
-
}
|
1000
|
+
const adjustFocusNodeInDirection = (tableSelection, tableNode, x, y, direction) => {
|
1001
|
+
switch (direction) {
|
1002
|
+
case 'backward':
|
1003
|
+
case 'forward':
|
1004
|
+
{
|
1005
|
+
const isForward = direction === 'forward';
|
540
1006
|
|
541
|
-
|
1007
|
+
if (x !== (isForward ? tableSelection.grid.columns - 1 : 0)) {
|
1008
|
+
tableSelection.adjustFocusCellForSelection(tableNode.getCellFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableSelection.grid));
|
542
1009
|
}
|
543
1010
|
|
544
|
-
|
545
|
-
|
546
|
-
if (y !== 0) {
|
547
|
-
tableNode.getCellNodeFromCordsOrThrow(x, y - 1).select();
|
548
|
-
} else {
|
549
|
-
tableNode.selectPrevious();
|
550
|
-
}
|
1011
|
+
return true;
|
1012
|
+
}
|
551
1013
|
|
1014
|
+
case 'up':
|
1015
|
+
{
|
1016
|
+
if (y !== 0) {
|
1017
|
+
tableSelection.adjustFocusCellForSelection(tableNode.getCellFromCordsOrThrow(x, y - 1, tableSelection.grid));
|
552
1018
|
return true;
|
1019
|
+
} else {
|
1020
|
+
return false;
|
553
1021
|
}
|
1022
|
+
}
|
554
1023
|
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
} else {
|
560
|
-
tableNode.selectNext();
|
561
|
-
}
|
562
|
-
|
1024
|
+
case 'down':
|
1025
|
+
{
|
1026
|
+
if (y !== tableSelection.grid.rows - 1) {
|
1027
|
+
tableSelection.adjustFocusCellForSelection(tableNode.getCellFromCordsOrThrow(x, y + 1, tableSelection.grid));
|
563
1028
|
return true;
|
1029
|
+
} else {
|
1030
|
+
return false;
|
564
1031
|
}
|
565
|
-
}
|
566
|
-
|
567
|
-
return false;
|
568
|
-
};
|
569
|
-
|
570
|
-
const genericCommandListener = editor.addListener('command', (type, payload) => {
|
571
|
-
const selection = lexical.$getSelection();
|
572
|
-
|
573
|
-
if (!lexical.$isRangeSelection(selection)) {
|
574
|
-
return false;
|
575
|
-
}
|
576
|
-
|
577
|
-
const tableCellNode = $findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
578
|
-
|
579
|
-
if (!$isTableCellNode(tableCellNode)) {
|
580
|
-
return false;
|
581
|
-
}
|
582
|
-
|
583
|
-
if (type === 'deleteCharacter') {
|
584
|
-
if (highlightedCells.length === 0 && selection.isCollapsed() && selection.anchor.offset === 0 && selection.anchor.getNode().getPreviousSiblings().length === 0) {
|
585
|
-
return true;
|
586
|
-
}
|
587
|
-
}
|
588
|
-
|
589
|
-
if (type === 'keyTab') {
|
590
|
-
const event = payload;
|
591
|
-
|
592
|
-
if (selection.isCollapsed() && highlightedCells.length === 0) {
|
593
|
-
const currentCords = tableNode.getCordsFromCellNode(tableCellNode);
|
594
|
-
event.preventDefault();
|
595
|
-
selectGridNodeInDirection(currentCords.x, currentCords.y, !event.shiftKey && type === 'keyTab' ? 'forward' : 'backward');
|
596
|
-
return true;
|
597
1032
|
}
|
598
|
-
|
599
|
-
|
600
|
-
if (type === 'keyArrowDown' || type === 'keyArrowUp') {
|
601
|
-
const event = payload;
|
1033
|
+
}
|
602
1034
|
|
603
|
-
|
604
|
-
|
605
|
-
const elementParentNode = $findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
1035
|
+
return false;
|
1036
|
+
};
|
606
1037
|
|
607
|
-
|
608
|
-
|
609
|
-
event.stopImmediatePropagation();
|
610
|
-
selectGridNodeInDirection(currentCords.x, currentCords.y, type === 'keyArrowUp' ? 'up' : 'down');
|
611
|
-
return true;
|
612
|
-
}
|
613
|
-
}
|
614
|
-
}
|
1038
|
+
function selectTableCellNode(tableCell) {
|
1039
|
+
const possibleParagraph = tableCell.getChildren().find(n => lexical.$isParagraphNode(n));
|
615
1040
|
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
1041
|
+
if (lexical.$isParagraphNode(possibleParagraph)) {
|
1042
|
+
possibleParagraph.selectEnd();
|
1043
|
+
} else {
|
1044
|
+
tableCell.selectEnd();
|
1045
|
+
}
|
620
1046
|
}
|
621
1047
|
|
622
1048
|
/**
|
@@ -632,21 +1058,26 @@ class TableNode extends lexical.GridNode {
|
|
632
1058
|
return 'table';
|
633
1059
|
}
|
634
1060
|
|
635
|
-
static clone(node
|
636
|
-
|
637
|
-
|
638
|
-
|
1061
|
+
static clone(node) {
|
1062
|
+
return new TableNode(node.__key);
|
1063
|
+
}
|
1064
|
+
|
1065
|
+
static convertDOM() {
|
1066
|
+
return {
|
1067
|
+
table: node => ({
|
1068
|
+
conversion: convertTableElement,
|
1069
|
+
priority: 0
|
1070
|
+
})
|
1071
|
+
};
|
639
1072
|
}
|
640
1073
|
|
641
|
-
constructor(
|
1074
|
+
constructor(key) {
|
642
1075
|
super(key);
|
643
|
-
this.__selectionShape = selectionShape;
|
644
|
-
this.__grid = grid;
|
645
1076
|
}
|
646
1077
|
|
647
1078
|
createDOM(config, editor) {
|
648
1079
|
const element = document.createElement('table');
|
649
|
-
addClassNamesToElement(element, config.theme.table);
|
1080
|
+
utils.addClassNamesToElement(element, config.theme.table);
|
650
1081
|
return element;
|
651
1082
|
}
|
652
1083
|
|
@@ -662,26 +1093,7 @@ class TableNode extends lexical.GridNode {
|
|
662
1093
|
return false;
|
663
1094
|
}
|
664
1095
|
|
665
|
-
|
666
|
-
const self = this.getWritable();
|
667
|
-
self.__selectionShape = selectionShape;
|
668
|
-
const grid = this.getGrid();
|
669
|
-
if (grid == null) return [];
|
670
|
-
|
671
|
-
if (!selectionShape) {
|
672
|
-
return updateCells(-1, -1, -1, -1, grid.cells);
|
673
|
-
}
|
674
|
-
|
675
|
-
return updateCells(selectionShape.fromX, selectionShape.toX, selectionShape.fromY, selectionShape.toY, grid.cells);
|
676
|
-
}
|
677
|
-
|
678
|
-
getSelectionState() {
|
679
|
-
return this.getLatest().__selectionShape;
|
680
|
-
}
|
681
|
-
|
682
|
-
getCordsFromCellNode(tableCellNode) {
|
683
|
-
const grid = this.getGrid();
|
684
|
-
|
1096
|
+
getCordsFromCellNode(tableCellNode, grid) {
|
685
1097
|
if (!grid) {
|
686
1098
|
throw Error(`Grid not found.`);
|
687
1099
|
}
|
@@ -716,9 +1128,7 @@ class TableNode extends lexical.GridNode {
|
|
716
1128
|
throw new Error('Cell not found in table.');
|
717
1129
|
}
|
718
1130
|
|
719
|
-
|
720
|
-
const grid = this.getGrid();
|
721
|
-
|
1131
|
+
getCellFromCords(x, y, grid) {
|
722
1132
|
if (!grid) {
|
723
1133
|
throw Error(`Grid not found.`);
|
724
1134
|
}
|
@@ -738,6 +1148,26 @@ class TableNode extends lexical.GridNode {
|
|
738
1148
|
return null;
|
739
1149
|
}
|
740
1150
|
|
1151
|
+
return cell;
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
getCellFromCordsOrThrow(x, y, grid) {
|
1155
|
+
const cell = this.getCellFromCords(x, y, grid);
|
1156
|
+
|
1157
|
+
if (!cell) {
|
1158
|
+
throw new Error('Cell not found at cords.');
|
1159
|
+
}
|
1160
|
+
|
1161
|
+
return cell;
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
getCellNodeFromCords(x, y, grid) {
|
1165
|
+
const cell = this.getCellFromCords(x, y, grid);
|
1166
|
+
|
1167
|
+
if (cell == null) {
|
1168
|
+
return null;
|
1169
|
+
}
|
1170
|
+
|
741
1171
|
const node = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
742
1172
|
|
743
1173
|
if ($isTableCellNode(node)) {
|
@@ -747,8 +1177,8 @@ class TableNode extends lexical.GridNode {
|
|
747
1177
|
return null;
|
748
1178
|
}
|
749
1179
|
|
750
|
-
getCellNodeFromCordsOrThrow(x, y) {
|
751
|
-
const node = this.getCellNodeFromCords(x, y);
|
1180
|
+
getCellNodeFromCordsOrThrow(x, y, grid) {
|
1181
|
+
const node = this.getCellNodeFromCords(x, y, grid);
|
752
1182
|
|
753
1183
|
if (!node) {
|
754
1184
|
throw new Error('Node at cords not TableCellNode.');
|
@@ -757,20 +1187,24 @@ class TableNode extends lexical.GridNode {
|
|
757
1187
|
return node;
|
758
1188
|
}
|
759
1189
|
|
760
|
-
|
761
|
-
|
762
|
-
self.__grid = grid;
|
763
|
-
return self;
|
1190
|
+
canSelectBefore() {
|
1191
|
+
return true;
|
764
1192
|
}
|
765
1193
|
|
766
|
-
|
767
|
-
|
768
|
-
|
1194
|
+
}
|
1195
|
+
function $getElementGridForTableNode(editor, tableNode) {
|
1196
|
+
const tableElement = editor.getElementByKey(tableNode.getKey());
|
769
1197
|
|
770
|
-
|
771
|
-
|
1198
|
+
if (tableElement == null) {
|
1199
|
+
throw new Error('Table Element Not Found');
|
772
1200
|
}
|
773
1201
|
|
1202
|
+
return getTableGrid(tableElement);
|
1203
|
+
}
|
1204
|
+
function convertTableElement(domNode) {
|
1205
|
+
return {
|
1206
|
+
node: $createTableNode()
|
1207
|
+
};
|
774
1208
|
}
|
775
1209
|
function $createTableNode() {
|
776
1210
|
return new TableNode();
|
@@ -793,21 +1227,46 @@ class TableRowNode extends lexical.GridRowNode {
|
|
793
1227
|
}
|
794
1228
|
|
795
1229
|
static clone(node) {
|
796
|
-
return new TableRowNode(node.__key);
|
1230
|
+
return new TableRowNode(node.__height, node.__key);
|
797
1231
|
}
|
798
1232
|
|
799
|
-
|
1233
|
+
static convertDOM() {
|
1234
|
+
return {
|
1235
|
+
tr: node => ({
|
1236
|
+
conversion: convertTableRowElement,
|
1237
|
+
priority: 0
|
1238
|
+
})
|
1239
|
+
};
|
1240
|
+
}
|
1241
|
+
|
1242
|
+
constructor(height, key) {
|
800
1243
|
super(key);
|
1244
|
+
this.__height = height;
|
801
1245
|
}
|
802
1246
|
|
803
1247
|
createDOM(config) {
|
804
1248
|
const element = document.createElement('tr');
|
805
|
-
|
1249
|
+
|
1250
|
+
if (this.__height) {
|
1251
|
+
element.style.height = `${this.__height}px`;
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
utils.addClassNamesToElement(element, config.theme.tableRow);
|
806
1255
|
return element;
|
807
1256
|
}
|
808
1257
|
|
809
|
-
|
810
|
-
|
1258
|
+
setHeight(height) {
|
1259
|
+
const self = this.getWritable();
|
1260
|
+
self.__height = height;
|
1261
|
+
return this.__height;
|
1262
|
+
}
|
1263
|
+
|
1264
|
+
getHeight() {
|
1265
|
+
return this.getLatest().__height;
|
1266
|
+
}
|
1267
|
+
|
1268
|
+
updateDOM(prevNode) {
|
1269
|
+
return prevNode.__height !== this.__height;
|
811
1270
|
}
|
812
1271
|
|
813
1272
|
canBeEmpty() {
|
@@ -815,8 +1274,13 @@ class TableRowNode extends lexical.GridRowNode {
|
|
815
1274
|
}
|
816
1275
|
|
817
1276
|
}
|
818
|
-
function
|
819
|
-
return
|
1277
|
+
function convertTableRowElement(domNode) {
|
1278
|
+
return {
|
1279
|
+
node: $createTableRowNode()
|
1280
|
+
};
|
1281
|
+
}
|
1282
|
+
function $createTableRowNode(height) {
|
1283
|
+
return new TableRowNode(height);
|
820
1284
|
}
|
821
1285
|
function $isTableRowNode(node) {
|
822
1286
|
return node instanceof TableRowNode;
|
@@ -837,14 +1301,14 @@ function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders =
|
|
837
1301
|
const tableRowNode = $createTableRowNode();
|
838
1302
|
|
839
1303
|
for (let iColumn = 0; iColumn < columnCount; iColumn++) {
|
840
|
-
|
1304
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
841
1305
|
|
842
1306
|
if (includeHeaders) {
|
843
|
-
if (iRow === 0)
|
844
|
-
if (iColumn === 0)
|
1307
|
+
if (iRow === 0) headerState |= TableCellHeaderStates.ROW;
|
1308
|
+
if (iColumn === 0) headerState |= TableCellHeaderStates.COLUMN;
|
845
1309
|
}
|
846
1310
|
|
847
|
-
const tableCellNode = $createTableCellNode(
|
1311
|
+
const tableCellNode = $createTableCellNode(headerState);
|
848
1312
|
const paragraphNode = lexical.$createParagraphNode();
|
849
1313
|
paragraphNode.append(lexical.$createTextNode());
|
850
1314
|
tableCellNode.append(paragraphNode);
|
@@ -857,7 +1321,7 @@ function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders =
|
|
857
1321
|
return tableNode;
|
858
1322
|
}
|
859
1323
|
function $getTableCellNodeFromLexicalNode(startingNode) {
|
860
|
-
const node =
|
1324
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableCellNode(n));
|
861
1325
|
|
862
1326
|
if ($isTableCellNode(node)) {
|
863
1327
|
return node;
|
@@ -866,7 +1330,7 @@ function $getTableCellNodeFromLexicalNode(startingNode) {
|
|
866
1330
|
return null;
|
867
1331
|
}
|
868
1332
|
function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
869
|
-
const node =
|
1333
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableRowNode(n));
|
870
1334
|
|
871
1335
|
if ($isTableRowNode(node)) {
|
872
1336
|
return node;
|
@@ -875,7 +1339,7 @@ function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
|
875
1339
|
throw new Error('Expected table cell to be inside of table row.');
|
876
1340
|
}
|
877
1341
|
function $getTableNodeFromLexicalNodeOrThrow(startingNode) {
|
878
|
-
const node =
|
1342
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableNode(n));
|
879
1343
|
|
880
1344
|
if ($isTableNode(node)) {
|
881
1345
|
return node;
|
@@ -892,17 +1356,17 @@ function $getTableColumnIndexFromTableCellNode(tableCellNode) {
|
|
892
1356
|
const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);
|
893
1357
|
return tableRowNode.getChildren().findIndex(n => n.is(tableCellNode));
|
894
1358
|
}
|
895
|
-
function $getTableCellSiblingsFromTableCellNode(tableCellNode) {
|
1359
|
+
function $getTableCellSiblingsFromTableCellNode(tableCellNode, grid) {
|
896
1360
|
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
|
897
1361
|
const {
|
898
1362
|
x,
|
899
1363
|
y
|
900
|
-
} = tableNode.getCordsFromCellNode(tableCellNode);
|
1364
|
+
} = tableNode.getCordsFromCellNode(tableCellNode, grid);
|
901
1365
|
return {
|
902
|
-
above: tableNode.getCellNodeFromCords(x, y - 1),
|
903
|
-
below: tableNode.getCellNodeFromCords(x, y + 1),
|
904
|
-
left: tableNode.getCellNodeFromCords(x - 1, y),
|
905
|
-
right: tableNode.getCellNodeFromCords(x + 1, y)
|
1366
|
+
above: tableNode.getCellNodeFromCords(x, y - 1, grid),
|
1367
|
+
below: tableNode.getCellNodeFromCords(x, y + 1, grid),
|
1368
|
+
left: tableNode.getCellNodeFromCords(x - 1, y, grid),
|
1369
|
+
right: tableNode.getCellNodeFromCords(x + 1, y, grid)
|
906
1370
|
};
|
907
1371
|
}
|
908
1372
|
function $removeTableRowAtIndex(tableNode, indexToDelete) {
|
@@ -916,7 +1380,7 @@ function $removeTableRowAtIndex(tableNode, indexToDelete) {
|
|
916
1380
|
targetRowNode.remove();
|
917
1381
|
return tableNode;
|
918
1382
|
}
|
919
|
-
function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount) {
|
1383
|
+
function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount, grid) {
|
920
1384
|
const tableRows = tableNode.getChildren();
|
921
1385
|
|
922
1386
|
if (targetIndex >= tableRows.length || targetIndex < 0) {
|
@@ -941,14 +1405,15 @@ function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCo
|
|
941
1405
|
const {
|
942
1406
|
above,
|
943
1407
|
below
|
944
|
-
} = $getTableCellSiblingsFromTableCellNode(tableCellFromTargetRow);
|
945
|
-
|
1408
|
+
} = $getTableCellSiblingsFromTableCellNode(tableCellFromTargetRow, grid);
|
1409
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
1410
|
+
const width = above && above.getWidth() || below && below.getWidth() || null;
|
946
1411
|
|
947
|
-
if (above && above.
|
948
|
-
|
1412
|
+
if (above && above.hasHeaderState(TableCellHeaderStates.COLUMN) || below && below.hasHeaderState(TableCellHeaderStates.COLUMN)) {
|
1413
|
+
headerState |= TableCellHeaderStates.COLUMN;
|
949
1414
|
}
|
950
1415
|
|
951
|
-
const tableCellNode = $createTableCellNode(
|
1416
|
+
const tableCellNode = $createTableCellNode(headerState, 1, width);
|
952
1417
|
tableCellNode.append(lexical.$createParagraphNode());
|
953
1418
|
newTableRowNode.append(tableCellNode);
|
954
1419
|
}
|
@@ -973,13 +1438,13 @@ function $insertTableColumn(tableNode, targetIndex, shouldInsertAfter = true, co
|
|
973
1438
|
|
974
1439
|
if ($isTableRowNode(currentTableRowNode)) {
|
975
1440
|
for (let c = 0; c < columnCount; c++) {
|
976
|
-
|
1441
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
977
1442
|
|
978
1443
|
if (r === 0) {
|
979
|
-
|
1444
|
+
headerState |= TableCellHeaderStates.ROW;
|
980
1445
|
}
|
981
1446
|
|
982
|
-
const newTableCell = $createTableCellNode(
|
1447
|
+
const newTableCell = $createTableCellNode(headerState);
|
983
1448
|
newTableCell.append(lexical.$createParagraphNode());
|
984
1449
|
const tableRowChildren = currentTableRowNode.getChildren();
|
985
1450
|
|
@@ -1020,12 +1485,22 @@ function $deleteTableColumn(tableNode, targetIndex) {
|
|
1020
1485
|
return tableNode;
|
1021
1486
|
}
|
1022
1487
|
|
1023
|
-
|
1488
|
+
/**
|
1489
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
1490
|
+
*
|
1491
|
+
* This source code is licensed under the MIT license found in the
|
1492
|
+
* LICENSE file in the root directory of this source tree.
|
1493
|
+
*
|
1494
|
+
*
|
1495
|
+
*/
|
1496
|
+
const INSERT_TABLE_COMMAND = lexical.createCommand();
|
1497
|
+
|
1024
1498
|
exports.$createTableCellNode = $createTableCellNode;
|
1025
1499
|
exports.$createTableNode = $createTableNode;
|
1026
1500
|
exports.$createTableNodeWithDimensions = $createTableNodeWithDimensions;
|
1027
1501
|
exports.$createTableRowNode = $createTableRowNode;
|
1028
1502
|
exports.$deleteTableColumn = $deleteTableColumn;
|
1503
|
+
exports.$getElementGridForTableNode = $getElementGridForTableNode;
|
1029
1504
|
exports.$getTableCellNodeFromLexicalNode = $getTableCellNodeFromLexicalNode;
|
1030
1505
|
exports.$getTableColumnIndexFromTableCellNode = $getTableColumnIndexFromTableCellNode;
|
1031
1506
|
exports.$getTableNodeFromLexicalNodeOrThrow = $getTableNodeFromLexicalNodeOrThrow;
|
@@ -1037,6 +1512,12 @@ exports.$isTableCellNode = $isTableCellNode;
|
|
1037
1512
|
exports.$isTableNode = $isTableNode;
|
1038
1513
|
exports.$isTableRowNode = $isTableRowNode;
|
1039
1514
|
exports.$removeTableRowAtIndex = $removeTableRowAtIndex;
|
1515
|
+
exports.INSERT_TABLE_COMMAND = INSERT_TABLE_COMMAND;
|
1516
|
+
exports.TableCellHeaderStates = TableCellHeaderStates;
|
1040
1517
|
exports.TableCellNode = TableCellNode;
|
1041
1518
|
exports.TableNode = TableNode;
|
1042
1519
|
exports.TableRowNode = TableRowNode;
|
1520
|
+
exports.TableSelection = TableSelection;
|
1521
|
+
exports.applyTableHandlers = applyTableHandlers;
|
1522
|
+
exports.getCellFromTarget = getCellFromTarget;
|
1523
|
+
exports.getTableSelectionFromTableElement = getTableSelectionFromTableElement;
|