@mx-space/cli 0.1.0
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 +33 -0
- package/README.md +375 -0
- package/ROADMAP.md +42 -0
- package/bin/mxs.cjs +40 -0
- package/dist/Lexical.dev-DpU35QTu.mjs +10992 -0
- package/dist/Lexical.dev-DpU35QTu.mjs.map +1 -0
- package/dist/Lexical.node-gYNDt_p9.mjs +247 -0
- package/dist/Lexical.node-gYNDt_p9.mjs.map +1 -0
- package/dist/Lexical.prod-t4c3bHV3.mjs +5579 -0
- package/dist/Lexical.prod-t4c3bHV3.mjs.map +1 -0
- package/dist/LexicalClipboard.dev-CdeeWCIq.mjs +496 -0
- package/dist/LexicalClipboard.dev-CdeeWCIq.mjs.map +1 -0
- package/dist/LexicalClipboard.node-0e9GBL1g.mjs +26 -0
- package/dist/LexicalClipboard.node-0e9GBL1g.mjs.map +1 -0
- package/dist/LexicalClipboard.prod-CsCWYmV7.mjs +293 -0
- package/dist/LexicalClipboard.prod-CsCWYmV7.mjs.map +1 -0
- package/dist/LexicalCodeCore.dev-haI2cqH8.mjs +539 -0
- package/dist/LexicalCodeCore.dev-haI2cqH8.mjs.map +1 -0
- package/dist/LexicalCodeCore.prod-D_k7zuE5.mjs +383 -0
- package/dist/LexicalCodeCore.prod-D_k7zuE5.mjs.map +1 -0
- package/dist/LexicalDragon.dev-CAggdFh_.mjs +90 -0
- package/dist/LexicalDragon.dev-CAggdFh_.mjs.map +1 -0
- package/dist/LexicalDragon.node-QMR_wqJg.mjs +15 -0
- package/dist/LexicalDragon.node-QMR_wqJg.mjs.map +1 -0
- package/dist/LexicalDragon.prod-OssQhwS-.mjs +61 -0
- package/dist/LexicalDragon.prod-OssQhwS-.mjs.map +1 -0
- package/dist/LexicalExtension.dev-CtDZiMCU.mjs +1665 -0
- package/dist/LexicalExtension.dev-CtDZiMCU.mjs.map +1 -0
- package/dist/LexicalExtension.node-BM0gh8zu.mjs +51 -0
- package/dist/LexicalExtension.node-BM0gh8zu.mjs.map +1 -0
- package/dist/LexicalExtension.prod-Ug6emhEO.mjs +971 -0
- package/dist/LexicalExtension.prod-Ug6emhEO.mjs.map +1 -0
- package/dist/LexicalHeadless.dev-D4yQpl_s.mjs +45 -0
- package/dist/LexicalHeadless.dev-D4yQpl_s.mjs.map +1 -0
- package/dist/LexicalHeadless.prod-jeN65B3k.mjs +31 -0
- package/dist/LexicalHeadless.prod-jeN65B3k.mjs.map +1 -0
- package/dist/LexicalHtml.dev-BdU1_ITQ.mjs +686 -0
- package/dist/LexicalHtml.dev-BdU1_ITQ.mjs.map +1 -0
- package/dist/LexicalHtml.node-DLtAh00E.mjs +26 -0
- package/dist/LexicalHtml.node-DLtAh00E.mjs.map +1 -0
- package/dist/LexicalHtml.prod-DdLE1HHT.mjs +432 -0
- package/dist/LexicalHtml.prod-DdLE1HHT.mjs.map +1 -0
- package/dist/LexicalLink.dev-DK87Biuy.mjs +1084 -0
- package/dist/LexicalLink.dev-DK87Biuy.mjs.map +1 -0
- package/dist/LexicalLink.prod-fssuv6Sf.mjs +717 -0
- package/dist/LexicalLink.prod-fssuv6Sf.mjs.map +1 -0
- package/dist/LexicalList.dev-BJ4dr_rk.mjs +1352 -0
- package/dist/LexicalList.dev-BJ4dr_rk.mjs.map +1 -0
- package/dist/LexicalList.prod-jWBbaWfi.mjs +841 -0
- package/dist/LexicalList.prod-jWBbaWfi.mjs.map +1 -0
- package/dist/LexicalMarkdown.dev-C8e-eh6y.mjs +1207 -0
- package/dist/LexicalMarkdown.dev-C8e-eh6y.mjs.map +1 -0
- package/dist/LexicalMarkdown.prod-k73tZVb2.mjs +756 -0
- package/dist/LexicalMarkdown.prod-k73tZVb2.mjs.map +1 -0
- package/dist/LexicalRichText.dev-CrSqq3K-.mjs +645 -0
- package/dist/LexicalRichText.dev-CrSqq3K-.mjs.map +1 -0
- package/dist/LexicalRichText.node-B7k7wlQz.mjs +106 -0
- package/dist/LexicalRichText.node-B7k7wlQz.mjs.map +1 -0
- package/dist/LexicalRichText.prod-CqvyxQ9m.mjs +429 -0
- package/dist/LexicalRichText.prod-CqvyxQ9m.mjs.map +1 -0
- package/dist/LexicalSelection.dev-sNOHKHe_.mjs +725 -0
- package/dist/LexicalSelection.dev-sNOHKHe_.mjs.map +1 -0
- package/dist/LexicalSelection.node-Di7GwBCZ.mjs +38 -0
- package/dist/LexicalSelection.node-Di7GwBCZ.mjs.map +1 -0
- package/dist/LexicalSelection.prod-SWllPJop.mjs +388 -0
- package/dist/LexicalSelection.prod-SWllPJop.mjs.map +1 -0
- package/dist/LexicalTable.dev-CQkLHXJx.mjs +3262 -0
- package/dist/LexicalTable.dev-CQkLHXJx.mjs.map +1 -0
- package/dist/LexicalTable.prod-BtqCwKSi.mjs +2218 -0
- package/dist/LexicalTable.prod-BtqCwKSi.mjs.map +1 -0
- package/dist/LexicalUtils.dev-DiUpsXE8.mjs +850 -0
- package/dist/LexicalUtils.dev-DiUpsXE8.mjs.map +1 -0
- package/dist/LexicalUtils.node-CmK462d1.mjs +66 -0
- package/dist/LexicalUtils.node-CmK462d1.mjs.map +1 -0
- package/dist/LexicalUtils.prod-bWwV4GAF.mjs +377 -0
- package/dist/LexicalUtils.prod-bWwV4GAF.mjs.map +1 -0
- package/dist/auth-DIFZzoMm.mjs +211 -0
- package/dist/auth-DIFZzoMm.mjs.map +1 -0
- package/dist/bin/mxs.d.mts +927 -0
- package/dist/bin/mxs.mjs +3249 -0
- package/dist/bin/mxs.mjs.map +1 -0
- package/dist/chunk-hT5z_Zn9.mjs +35 -0
- package/dist/config-store-DIu7x0ao.mjs +121 -0
- package/dist/config-store-DIu7x0ao.mjs.map +1 -0
- package/dist/create-B2AOQL1e.mjs +24 -0
- package/dist/create-B2AOQL1e.mjs.map +1 -0
- package/dist/create-CwjGcv2n.mjs +23 -0
- package/dist/create-CwjGcv2n.mjs.map +1 -0
- package/dist/create-DT1l2hue.mjs +23 -0
- package/dist/create-DT1l2hue.mjs.map +1 -0
- package/dist/create-DjlRHPXy.mjs +23 -0
- package/dist/create-DjlRHPXy.mjs.map +1 -0
- package/dist/create-Dz6rJJSS.mjs +19 -0
- package/dist/create-Dz6rJJSS.mjs.map +1 -0
- package/dist/delete-B4dGrrus.mjs +22 -0
- package/dist/delete-B4dGrrus.mjs.map +1 -0
- package/dist/delete-BH6ZngTz.mjs +22 -0
- package/dist/delete-BH6ZngTz.mjs.map +1 -0
- package/dist/delete-BrY5zJ6S.mjs +22 -0
- package/dist/delete-BrY5zJ6S.mjs.map +1 -0
- package/dist/delete-CaG2d_xt.mjs +31 -0
- package/dist/delete-CaG2d_xt.mjs.map +1 -0
- package/dist/delete-YzRliRn8.mjs +31 -0
- package/dist/delete-YzRliRn8.mjs.map +1 -0
- package/dist/document-output-BVB8emLt.mjs +145 -0
- package/dist/document-output-BVB8emLt.mjs.map +1 -0
- package/dist/edit-Bb0Ze4w6.mjs +79 -0
- package/dist/edit-Bb0Ze4w6.mjs.map +1 -0
- package/dist/edit-BeFmC3XD.mjs +80 -0
- package/dist/edit-BeFmC3XD.mjs.map +1 -0
- package/dist/edit-DLDw_ZWX.mjs +86 -0
- package/dist/edit-DLDw_ZWX.mjs.map +1 -0
- package/dist/edit-z55ofr1S.mjs +40 -0
- package/dist/edit-z55ofr1S.mjs.map +1 -0
- package/dist/editor-xrF-j3UE.mjs +42 -0
- package/dist/editor-xrF-j3UE.mjs.map +1 -0
- package/dist/envelope-overlays-DPAlMNW1.mjs +26 -0
- package/dist/envelope-overlays-DPAlMNW1.mjs.map +1 -0
- package/dist/get-2qjq0wgG.mjs +28 -0
- package/dist/get-2qjq0wgG.mjs.map +1 -0
- package/dist/get-BGAk1Zmv.mjs +14 -0
- package/dist/get-BGAk1Zmv.mjs.map +1 -0
- package/dist/get-CRR13lgj.mjs +10 -0
- package/dist/get-CRR13lgj.mjs.map +1 -0
- package/dist/get-ClkpDBTL.mjs +13 -0
- package/dist/get-ClkpDBTL.mjs.map +1 -0
- package/dist/get-DJfUJ3sP.mjs +10 -0
- package/dist/get-DJfUJ3sP.mjs.map +1 -0
- package/dist/get-DiqaQvoS.mjs +14 -0
- package/dist/get-DiqaQvoS.mjs.map +1 -0
- package/dist/index.d.mts +338 -0
- package/dist/index.mjs +10 -0
- package/dist/list-BYzhflDg.mjs +14 -0
- package/dist/list-BYzhflDg.mjs.map +1 -0
- package/dist/list-DY-tPNG-.mjs +10 -0
- package/dist/list-DY-tPNG-.mjs.map +1 -0
- package/dist/list-DlQSkbqx.mjs +10 -0
- package/dist/list-DlQSkbqx.mjs.map +1 -0
- package/dist/list-DsrA5wIz.mjs +15 -0
- package/dist/list-DsrA5wIz.mjs.map +1 -0
- package/dist/list-Fp4nKfQb.mjs +10 -0
- package/dist/list-Fp4nKfQb.mjs.map +1 -0
- package/dist/list-s_tloiEX.mjs +10 -0
- package/dist/list-s_tloiEX.mjs.map +1 -0
- package/dist/litexml-codec-CDoRloiR.mjs +13451 -0
- package/dist/litexml-codec-CDoRloiR.mjs.map +1 -0
- package/dist/login-CLOJ-fTJ.mjs +579 -0
- package/dist/login-CLOJ-fTJ.mjs.map +1 -0
- package/dist/logout-v8ihxsim.mjs +11 -0
- package/dist/logout-v8ihxsim.mjs.map +1 -0
- package/dist/onboarding-640IldLz.mjs +888 -0
- package/dist/onboarding-640IldLz.mjs.map +1 -0
- package/dist/output-BM7aBFwt.mjs +120 -0
- package/dist/output-BM7aBFwt.mjs.map +1 -0
- package/dist/output-CTnO1lYt.d.mts +16 -0
- package/dist/payload-CN11pUto.mjs +547 -0
- package/dist/payload-CN11pUto.mjs.map +1 -0
- package/dist/publish-DkTYB-eK.mjs +23 -0
- package/dist/publish-DkTYB-eK.mjs.map +1 -0
- package/dist/publish-pRBfTJfe.mjs +23 -0
- package/dist/publish-pRBfTJfe.mjs.map +1 -0
- package/dist/resolve-BogJOR7R.mjs +119 -0
- package/dist/resolve-BogJOR7R.mjs.map +1 -0
- package/dist/resolve-Bp1AfBmM.mjs +26 -0
- package/dist/resolve-Bp1AfBmM.mjs.map +1 -0
- package/dist/resolve-Bw5Po9yK.mjs +16 -0
- package/dist/resolve-Bw5Po9yK.mjs.map +1 -0
- package/dist/resolve-CyjMlaoJ.mjs +23 -0
- package/dist/resolve-CyjMlaoJ.mjs.map +1 -0
- package/dist/resolve-helpers-CahPoJ0Y.mjs +30 -0
- package/dist/resolve-helpers-CahPoJ0Y.mjs.map +1 -0
- package/dist/set-BEGQz2si.mjs +43 -0
- package/dist/set-BEGQz2si.mjs.map +1 -0
- package/dist/shared-D0HVBDHI.mjs +39 -0
- package/dist/shared-D0HVBDHI.mjs.map +1 -0
- package/dist/status-LXrN9fI-.mjs +22 -0
- package/dist/status-LXrN9fI-.mjs.map +1 -0
- package/dist/update-B9ynFCdZ.mjs +30 -0
- package/dist/update-B9ynFCdZ.mjs.map +1 -0
- package/dist/update-BMZQPOvR.mjs +28 -0
- package/dist/update-BMZQPOvR.mjs.map +1 -0
- package/dist/update-BXz0l7Lz.mjs +36 -0
- package/dist/update-BXz0l7Lz.mjs.map +1 -0
- package/dist/update-Dx6AF8tf.mjs +30 -0
- package/dist/update-Dx6AF8tf.mjs.map +1 -0
- package/dist/update-q66TLS38.mjs +37 -0
- package/dist/update-q66TLS38.mjs.map +1 -0
- package/dist/whoami-CTkctOEd.mjs +22 -0
- package/dist/whoami-CTkctOEd.mjs.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,3262 @@
|
|
|
1
|
+
import { c as signal, r as effect, s as namedSignals } from "./LexicalExtension.node-BM0gh8zu.mjs";
|
|
2
|
+
import { $n as safeCast, At as COMMAND_PRIORITY_LOW, B as $getSiblingCaret, Bn as isCurrentlyReadOnlyMode, D as $getChildCaret, F as $getNodeByKeyOrThrow, Ft as DELETE_CHARACTER_COMMAND, Gn as isHTMLElement, Gt as FORMAT_TEXT_COMMAND, Hn as isDOMNode, Ht as ElementNode, It as DELETE_LINE_COMMAND, K as $isChildCaret, L as $getPreviousSelection, Lt as DELETE_WORD_COMMAND, Mn as defineExtension, N as $getNearestNodeFromDOMNode, Nn as getDOMSelection, Nt as CUT_COMMAND, On as createCommand, Ot as COMMAND_PRIORITY_EDITOR, P as $getNodeByKey, R as $getRoot, Sn as TEXT_TYPE_TO_FORMAT, Tt as CLICK_COMMAND, Ut as FOCUS_COMMAND, Wt as FORMAT_ELEMENT_COMMAND, X as $isExtendableTextPointCaret, Y as $isElementNode, Z as $isInlineElementOrDecoratorNode, Zt as INSERT_PARAGRAPH_COMMAND, _ as $createTextNode, _n as SELECTION_CHANGE_COMMAND, _t as $setPointFromCaret, an as KEY_DELETE_COMMAND, at as $isRootOrShadowRoot, b as $getAdjacentChildCaret, ct as $isTextNode, dt as $normalizeCaret, en as KEY_ARROW_DOWN_COMMAND, er as setDOMStyleFromCSS, et as $isLineBreakNode, f as $createParagraphNode, ft as $normalizeSelection__EXPERIMENTAL, h as $createRangeSelectionFromDom, in as KEY_BACKSPACE_COMMAND, it as $isRootNode, j as $getEditor, jt as CONTROLLED_TEXT_INSERTION_COMMAND, kt as COMMAND_PRIORITY_HIGH, ln as KEY_TAB_COMMAND, m as $createRangeSelection, n as $applyNodeReplacement, nn as KEY_ARROW_RIGHT_COMMAND, nt as $isParagraphNode, ot as $isSiblingCaret, p as $createPoint, r as $caretFromPoint, rn as KEY_ARROW_UP_COMMAND, rt as $isRangeSelection, sn as KEY_ESCAPE_COMMAND, tn as KEY_ARROW_LEFT_COMMAND, tr as setDOMUnmanaged, v as $extendCaretToRange, vn as SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, vt as $setSelection, yn as SELECT_ALL_COMMAND, z as $getSelection } from "./Lexical.node-gYNDt_p9.mjs";
|
|
3
|
+
import { _ as removeClassNamesFromElement, c as $insertNodeToNearestRoot, d as addClassNamesToElement, g as objectKlassEquals, h as mergeRegister, m as isHTMLElement$1, n as $dfs, r as $findMatchingParent, s as $insertFirst$1, t as $descendantsMatching, u as $unwrapAndFilterDescendants } from "./LexicalUtils.node-CmK462d1.mjs";
|
|
4
|
+
import { a as copyToClipboard, t as $getClipboardDataFromSelection } from "./LexicalClipboard.node-0e9GBL1g.mjs";
|
|
5
|
+
//#region ../../node_modules/.pnpm/@lexical+table@0.44.0/node_modules/@lexical/table/LexicalTable.dev.mjs
|
|
6
|
+
/**
|
|
7
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the MIT license found in the
|
|
10
|
+
* LICENSE file in the root directory of this source tree.
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
15
|
+
*
|
|
16
|
+
* This source code is licensed under the MIT license found in the
|
|
17
|
+
* LICENSE file in the root directory of this source tree.
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
const PIXEL_VALUE_REG_EXP = /^(\d+(?:\.\d+)?)px$/;
|
|
21
|
+
const COLUMN_WIDTH = 75;
|
|
22
|
+
/**
|
|
23
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
24
|
+
*
|
|
25
|
+
* This source code is licensed under the MIT license found in the
|
|
26
|
+
* LICENSE file in the root directory of this source tree.
|
|
27
|
+
*
|
|
28
|
+
*/
|
|
29
|
+
const TableCellHeaderStates = {
|
|
30
|
+
BOTH: 3,
|
|
31
|
+
COLUMN: 2,
|
|
32
|
+
NO_STATUS: 0,
|
|
33
|
+
ROW: 1
|
|
34
|
+
};
|
|
35
|
+
/** @noInheritDoc */
|
|
36
|
+
var TableCellNode = class TableCellNode extends ElementNode {
|
|
37
|
+
/** @internal */
|
|
38
|
+
__colSpan;
|
|
39
|
+
/** @internal */
|
|
40
|
+
__rowSpan;
|
|
41
|
+
/** @internal */
|
|
42
|
+
__headerState;
|
|
43
|
+
/** @internal */
|
|
44
|
+
__width;
|
|
45
|
+
/** @internal */
|
|
46
|
+
__backgroundColor;
|
|
47
|
+
/** @internal */
|
|
48
|
+
__verticalAlign;
|
|
49
|
+
static getType() {
|
|
50
|
+
return "tablecell";
|
|
51
|
+
}
|
|
52
|
+
static clone(node) {
|
|
53
|
+
return new TableCellNode(node.__headerState, node.__colSpan, node.__width, node.__key);
|
|
54
|
+
}
|
|
55
|
+
afterCloneFrom(node) {
|
|
56
|
+
super.afterCloneFrom(node);
|
|
57
|
+
this.__rowSpan = node.__rowSpan;
|
|
58
|
+
this.__backgroundColor = node.__backgroundColor;
|
|
59
|
+
this.__verticalAlign = node.__verticalAlign;
|
|
60
|
+
this.__colSpan = node.__colSpan;
|
|
61
|
+
this.__headerState = node.__headerState;
|
|
62
|
+
this.__width = node.__width;
|
|
63
|
+
}
|
|
64
|
+
static importDOM() {
|
|
65
|
+
return {
|
|
66
|
+
td: (node) => ({
|
|
67
|
+
conversion: $convertTableCellNodeElement,
|
|
68
|
+
priority: 0
|
|
69
|
+
}),
|
|
70
|
+
th: (node) => ({
|
|
71
|
+
conversion: $convertTableCellNodeElement,
|
|
72
|
+
priority: 0
|
|
73
|
+
})
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
static importJSON(serializedNode) {
|
|
77
|
+
return $createTableCellNode().updateFromJSON(serializedNode);
|
|
78
|
+
}
|
|
79
|
+
updateFromJSON(serializedNode) {
|
|
80
|
+
return super.updateFromJSON(serializedNode).setHeaderStyles(serializedNode.headerState).setColSpan(serializedNode.colSpan || 1).setRowSpan(serializedNode.rowSpan || 1).setWidth(serializedNode.width || void 0).setBackgroundColor(serializedNode.backgroundColor || null).setVerticalAlign(serializedNode.verticalAlign || void 0);
|
|
81
|
+
}
|
|
82
|
+
constructor(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width, key) {
|
|
83
|
+
super(key);
|
|
84
|
+
this.__colSpan = colSpan;
|
|
85
|
+
this.__rowSpan = 1;
|
|
86
|
+
this.__headerState = headerState;
|
|
87
|
+
this.__width = width;
|
|
88
|
+
this.__backgroundColor = null;
|
|
89
|
+
this.__verticalAlign = void 0;
|
|
90
|
+
}
|
|
91
|
+
createDOM(config) {
|
|
92
|
+
const element = document.createElement(this.getTag());
|
|
93
|
+
if (this.__width) element.style.width = `${this.__width}px`;
|
|
94
|
+
if (this.__colSpan > 1) element.colSpan = this.__colSpan;
|
|
95
|
+
if (this.__rowSpan > 1) element.rowSpan = this.__rowSpan;
|
|
96
|
+
if (this.__backgroundColor !== null) element.style.backgroundColor = this.__backgroundColor;
|
|
97
|
+
if (isValidVerticalAlign(this.__verticalAlign)) element.style.verticalAlign = this.__verticalAlign;
|
|
98
|
+
addClassNamesToElement(element, config.theme.tableCell, this.hasHeader() && config.theme.tableCellHeader);
|
|
99
|
+
return element;
|
|
100
|
+
}
|
|
101
|
+
exportDOM(editor) {
|
|
102
|
+
const output = super.exportDOM(editor);
|
|
103
|
+
if (isHTMLElement(output.element)) {
|
|
104
|
+
const element = output.element;
|
|
105
|
+
element.setAttribute("data-temporary-table-cell-lexical-key", this.getKey());
|
|
106
|
+
element.style.border = "1px solid black";
|
|
107
|
+
if (this.__colSpan > 1) element.colSpan = this.__colSpan;
|
|
108
|
+
if (this.__rowSpan > 1) element.rowSpan = this.__rowSpan;
|
|
109
|
+
element.style.width = `${this.getWidth() || COLUMN_WIDTH}px`;
|
|
110
|
+
element.style.verticalAlign = this.getVerticalAlign() || "top";
|
|
111
|
+
element.style.textAlign = "start";
|
|
112
|
+
if (this.__backgroundColor === null && this.hasHeader()) element.style.backgroundColor = "#f2f3f5";
|
|
113
|
+
}
|
|
114
|
+
return output;
|
|
115
|
+
}
|
|
116
|
+
exportJSON() {
|
|
117
|
+
return {
|
|
118
|
+
...super.exportJSON(),
|
|
119
|
+
...isValidVerticalAlign(this.__verticalAlign) && { verticalAlign: this.__verticalAlign },
|
|
120
|
+
backgroundColor: this.getBackgroundColor(),
|
|
121
|
+
colSpan: this.__colSpan,
|
|
122
|
+
headerState: this.__headerState,
|
|
123
|
+
rowSpan: this.__rowSpan,
|
|
124
|
+
width: this.getWidth()
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
getColSpan() {
|
|
128
|
+
return this.getLatest().__colSpan;
|
|
129
|
+
}
|
|
130
|
+
setColSpan(colSpan) {
|
|
131
|
+
const self = this.getWritable();
|
|
132
|
+
self.__colSpan = colSpan;
|
|
133
|
+
return self;
|
|
134
|
+
}
|
|
135
|
+
getRowSpan() {
|
|
136
|
+
return this.getLatest().__rowSpan;
|
|
137
|
+
}
|
|
138
|
+
setRowSpan(rowSpan) {
|
|
139
|
+
const self = this.getWritable();
|
|
140
|
+
self.__rowSpan = rowSpan;
|
|
141
|
+
return self;
|
|
142
|
+
}
|
|
143
|
+
getTag() {
|
|
144
|
+
return this.hasHeader() ? "th" : "td";
|
|
145
|
+
}
|
|
146
|
+
setHeaderStyles(headerState, mask = TableCellHeaderStates.BOTH) {
|
|
147
|
+
const self = this.getWritable();
|
|
148
|
+
self.__headerState = headerState & mask | self.__headerState & ~mask;
|
|
149
|
+
return self;
|
|
150
|
+
}
|
|
151
|
+
getHeaderStyles() {
|
|
152
|
+
return this.getLatest().__headerState;
|
|
153
|
+
}
|
|
154
|
+
setWidth(width) {
|
|
155
|
+
const self = this.getWritable();
|
|
156
|
+
self.__width = width;
|
|
157
|
+
return self;
|
|
158
|
+
}
|
|
159
|
+
getWidth() {
|
|
160
|
+
return this.getLatest().__width;
|
|
161
|
+
}
|
|
162
|
+
getBackgroundColor() {
|
|
163
|
+
return this.getLatest().__backgroundColor;
|
|
164
|
+
}
|
|
165
|
+
setBackgroundColor(newBackgroundColor) {
|
|
166
|
+
const self = this.getWritable();
|
|
167
|
+
self.__backgroundColor = newBackgroundColor;
|
|
168
|
+
return self;
|
|
169
|
+
}
|
|
170
|
+
getVerticalAlign() {
|
|
171
|
+
return this.getLatest().__verticalAlign;
|
|
172
|
+
}
|
|
173
|
+
setVerticalAlign(newVerticalAlign) {
|
|
174
|
+
const self = this.getWritable();
|
|
175
|
+
self.__verticalAlign = newVerticalAlign || void 0;
|
|
176
|
+
return self;
|
|
177
|
+
}
|
|
178
|
+
toggleHeaderStyle(headerStateToToggle) {
|
|
179
|
+
const self = this.getWritable();
|
|
180
|
+
if ((self.__headerState & headerStateToToggle) === headerStateToToggle) self.__headerState -= headerStateToToggle;
|
|
181
|
+
else self.__headerState += headerStateToToggle;
|
|
182
|
+
return self;
|
|
183
|
+
}
|
|
184
|
+
hasHeaderState(headerState) {
|
|
185
|
+
return (this.getHeaderStyles() & headerState) === headerState;
|
|
186
|
+
}
|
|
187
|
+
hasHeader() {
|
|
188
|
+
return this.getLatest().__headerState !== TableCellHeaderStates.NO_STATUS;
|
|
189
|
+
}
|
|
190
|
+
updateDOM(prevNode) {
|
|
191
|
+
return prevNode.__headerState !== this.__headerState || prevNode.__width !== this.__width || prevNode.__colSpan !== this.__colSpan || prevNode.__rowSpan !== this.__rowSpan || prevNode.__backgroundColor !== this.__backgroundColor || prevNode.__verticalAlign !== this.__verticalAlign;
|
|
192
|
+
}
|
|
193
|
+
isShadowRoot() {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
collapseAtStart() {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
canBeEmpty() {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
canIndent() {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
function isValidVerticalAlign(verticalAlign) {
|
|
207
|
+
return verticalAlign === "middle" || verticalAlign === "bottom";
|
|
208
|
+
}
|
|
209
|
+
function $convertTableCellNodeElement(domNode) {
|
|
210
|
+
const domNode_ = domNode;
|
|
211
|
+
const nodeName = domNode.nodeName.toLowerCase();
|
|
212
|
+
let width = void 0;
|
|
213
|
+
if (PIXEL_VALUE_REG_EXP.test(domNode_.style.width)) width = parseFloat(domNode_.style.width);
|
|
214
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
|
215
|
+
if (nodeName === "th") {
|
|
216
|
+
const scope = domNode_.getAttribute("scope");
|
|
217
|
+
if (scope === "col") headerState = TableCellHeaderStates.COLUMN;
|
|
218
|
+
else if (scope === "row") headerState = TableCellHeaderStates.ROW;
|
|
219
|
+
else {
|
|
220
|
+
const parentRow = domNode_.parentElement;
|
|
221
|
+
const isInHeaderRow = isHTMLElement(parentRow) && parentRow.nodeName.toLowerCase() === "tr" && isHTMLElement(parentRow.parentElement) && (parentRow.parentElement.nodeName.toLowerCase() === "thead" || parentRow.rowIndex === 0);
|
|
222
|
+
const isFirstColumn = domNode_.cellIndex === 0;
|
|
223
|
+
if (isInHeaderRow) headerState |= TableCellHeaderStates.ROW;
|
|
224
|
+
if (isFirstColumn) headerState |= TableCellHeaderStates.COLUMN;
|
|
225
|
+
if (headerState === TableCellHeaderStates.NO_STATUS) headerState = TableCellHeaderStates.ROW;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const tableCellNode = $createTableCellNode(headerState, domNode_.colSpan, width);
|
|
229
|
+
tableCellNode.__rowSpan = domNode_.rowSpan;
|
|
230
|
+
const backgroundColor = domNode_.style.backgroundColor;
|
|
231
|
+
if (backgroundColor !== "") tableCellNode.__backgroundColor = backgroundColor;
|
|
232
|
+
const verticalAlign = domNode_.style.verticalAlign;
|
|
233
|
+
if (isValidVerticalAlign(verticalAlign)) tableCellNode.__verticalAlign = verticalAlign;
|
|
234
|
+
const style = domNode_.style;
|
|
235
|
+
const textDecoration = (style && style.textDecoration || "").split(" ");
|
|
236
|
+
const hasBoldFontWeight = style.fontWeight === "700" || style.fontWeight === "bold";
|
|
237
|
+
const hasLinethroughTextDecoration = textDecoration.includes("line-through");
|
|
238
|
+
const hasItalicFontStyle = style.fontStyle === "italic";
|
|
239
|
+
const hasUnderlineTextDecoration = textDecoration.includes("underline");
|
|
240
|
+
const color = style.color;
|
|
241
|
+
return {
|
|
242
|
+
after: (childLexicalNodes) => {
|
|
243
|
+
const result = [];
|
|
244
|
+
let paragraphNode = null;
|
|
245
|
+
const removeSingleLineBreakNode = () => {
|
|
246
|
+
if (paragraphNode) {
|
|
247
|
+
const firstChild = paragraphNode.getFirstChild();
|
|
248
|
+
if ($isLineBreakNode(firstChild) && paragraphNode.getChildrenSize() === 1) firstChild.remove();
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
for (const child of childLexicalNodes) if ($isInlineElementOrDecoratorNode(child) || $isTextNode(child) || $isLineBreakNode(child)) {
|
|
252
|
+
if ($isTextNode(child)) {
|
|
253
|
+
if (hasBoldFontWeight) child.toggleFormat("bold");
|
|
254
|
+
if (hasLinethroughTextDecoration) child.toggleFormat("strikethrough");
|
|
255
|
+
if (hasItalicFontStyle) child.toggleFormat("italic");
|
|
256
|
+
if (hasUnderlineTextDecoration) child.toggleFormat("underline");
|
|
257
|
+
if (color) {
|
|
258
|
+
const existingStyle = child.getStyle();
|
|
259
|
+
if (!existingStyle.includes("color:")) child.setStyle(existingStyle + `color: ${color};`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (paragraphNode) paragraphNode.append(child);
|
|
263
|
+
else {
|
|
264
|
+
paragraphNode = $createParagraphNode().append(child);
|
|
265
|
+
result.push(paragraphNode);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
result.push(child);
|
|
269
|
+
removeSingleLineBreakNode();
|
|
270
|
+
paragraphNode = null;
|
|
271
|
+
}
|
|
272
|
+
removeSingleLineBreakNode();
|
|
273
|
+
if (result.length === 0) result.push($createParagraphNode());
|
|
274
|
+
return result;
|
|
275
|
+
},
|
|
276
|
+
node: tableCellNode
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function $createTableCellNode(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width) {
|
|
280
|
+
return $applyNodeReplacement(new TableCellNode(headerState, colSpan, width));
|
|
281
|
+
}
|
|
282
|
+
function $isTableCellNode(node) {
|
|
283
|
+
return node instanceof TableCellNode;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
287
|
+
*
|
|
288
|
+
* This source code is licensed under the MIT license found in the
|
|
289
|
+
* LICENSE file in the root directory of this source tree.
|
|
290
|
+
*
|
|
291
|
+
*/
|
|
292
|
+
const INSERT_TABLE_COMMAND = createCommand("INSERT_TABLE_COMMAND");
|
|
293
|
+
/**
|
|
294
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
295
|
+
*
|
|
296
|
+
* This source code is licensed under the MIT license found in the
|
|
297
|
+
* LICENSE file in the root directory of this source tree.
|
|
298
|
+
*
|
|
299
|
+
*/
|
|
300
|
+
function formatDevErrorMessage(message) {
|
|
301
|
+
throw new Error(message);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
305
|
+
*
|
|
306
|
+
* This source code is licensed under the MIT license found in the
|
|
307
|
+
* LICENSE file in the root directory of this source tree.
|
|
308
|
+
*
|
|
309
|
+
*/
|
|
310
|
+
/** @noInheritDoc */
|
|
311
|
+
var TableRowNode = class TableRowNode extends ElementNode {
|
|
312
|
+
/** @internal */
|
|
313
|
+
__height;
|
|
314
|
+
static getType() {
|
|
315
|
+
return "tablerow";
|
|
316
|
+
}
|
|
317
|
+
static clone(node) {
|
|
318
|
+
return new TableRowNode(node.__height, node.__key);
|
|
319
|
+
}
|
|
320
|
+
afterCloneFrom(prevNode) {
|
|
321
|
+
super.afterCloneFrom(prevNode);
|
|
322
|
+
this.__height = prevNode.__height;
|
|
323
|
+
}
|
|
324
|
+
static importDOM() {
|
|
325
|
+
return { tr: (node) => ({
|
|
326
|
+
conversion: $convertTableRowElement,
|
|
327
|
+
priority: 0
|
|
328
|
+
}) };
|
|
329
|
+
}
|
|
330
|
+
static importJSON(serializedNode) {
|
|
331
|
+
return $createTableRowNode().updateFromJSON(serializedNode);
|
|
332
|
+
}
|
|
333
|
+
updateFromJSON(serializedNode) {
|
|
334
|
+
return super.updateFromJSON(serializedNode).setHeight(serializedNode.height);
|
|
335
|
+
}
|
|
336
|
+
constructor(height, key) {
|
|
337
|
+
super(key);
|
|
338
|
+
this.__height = height;
|
|
339
|
+
}
|
|
340
|
+
exportJSON() {
|
|
341
|
+
const height = this.getHeight();
|
|
342
|
+
return {
|
|
343
|
+
...super.exportJSON(),
|
|
344
|
+
...height === void 0 ? void 0 : { height }
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
createDOM(config) {
|
|
348
|
+
const element = document.createElement("tr");
|
|
349
|
+
if (this.__height) element.style.height = `${this.__height}px`;
|
|
350
|
+
addClassNamesToElement(element, config.theme.tableRow);
|
|
351
|
+
return element;
|
|
352
|
+
}
|
|
353
|
+
extractWithChild(child, selection, destination) {
|
|
354
|
+
return destination === "html";
|
|
355
|
+
}
|
|
356
|
+
isShadowRoot() {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
setHeight(height) {
|
|
360
|
+
const self = this.getWritable();
|
|
361
|
+
self.__height = height;
|
|
362
|
+
return self;
|
|
363
|
+
}
|
|
364
|
+
getHeight() {
|
|
365
|
+
return this.getLatest().__height;
|
|
366
|
+
}
|
|
367
|
+
updateDOM(prevNode) {
|
|
368
|
+
return prevNode.__height !== this.__height;
|
|
369
|
+
}
|
|
370
|
+
canBeEmpty() {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
canIndent() {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
function $convertTableRowElement(domNode) {
|
|
378
|
+
const domNode_ = domNode;
|
|
379
|
+
let height = void 0;
|
|
380
|
+
if (PIXEL_VALUE_REG_EXP.test(domNode_.style.height)) height = parseFloat(domNode_.style.height);
|
|
381
|
+
return {
|
|
382
|
+
after: (children) => $descendantsMatching(children, $isTableCellNode),
|
|
383
|
+
node: $createTableRowNode(height)
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function $createTableRowNode(height) {
|
|
387
|
+
return $applyNodeReplacement(new TableRowNode(height));
|
|
388
|
+
}
|
|
389
|
+
function $isTableRowNode(node) {
|
|
390
|
+
return node instanceof TableRowNode;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
394
|
+
*
|
|
395
|
+
* This source code is licensed under the MIT license found in the
|
|
396
|
+
* LICENSE file in the root directory of this source tree.
|
|
397
|
+
*
|
|
398
|
+
*/
|
|
399
|
+
const CAN_USE_DOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
|
|
400
|
+
/**
|
|
401
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
402
|
+
*
|
|
403
|
+
* This source code is licensed under the MIT license found in the
|
|
404
|
+
* LICENSE file in the root directory of this source tree.
|
|
405
|
+
*
|
|
406
|
+
*/
|
|
407
|
+
const documentMode = CAN_USE_DOM && "documentMode" in document ? document.documentMode : null;
|
|
408
|
+
const IS_FIREFOX = CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
|
|
409
|
+
CAN_USE_DOM && "InputEvent" in window && !documentMode && "getTargetRanges" in new window.InputEvent("input");
|
|
410
|
+
function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) {
|
|
411
|
+
const tableNode = $createTableNode();
|
|
412
|
+
for (let iRow = 0; iRow < rowCount; iRow++) {
|
|
413
|
+
const tableRowNode = $createTableRowNode();
|
|
414
|
+
for (let iColumn = 0; iColumn < columnCount; iColumn++) {
|
|
415
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
|
416
|
+
if (typeof includeHeaders === "object") {
|
|
417
|
+
if (iRow === 0 && includeHeaders.rows) headerState |= TableCellHeaderStates.ROW;
|
|
418
|
+
if (iColumn === 0 && includeHeaders.columns) headerState |= TableCellHeaderStates.COLUMN;
|
|
419
|
+
} else if (includeHeaders) {
|
|
420
|
+
if (iRow === 0) headerState |= TableCellHeaderStates.ROW;
|
|
421
|
+
if (iColumn === 0) headerState |= TableCellHeaderStates.COLUMN;
|
|
422
|
+
}
|
|
423
|
+
const tableCellNode = $createTableCellNode(headerState);
|
|
424
|
+
const paragraphNode = $createParagraphNode();
|
|
425
|
+
paragraphNode.append($createTextNode());
|
|
426
|
+
tableCellNode.append(paragraphNode);
|
|
427
|
+
tableRowNode.append(tableCellNode);
|
|
428
|
+
}
|
|
429
|
+
tableNode.append(tableRowNode);
|
|
430
|
+
}
|
|
431
|
+
return tableNode;
|
|
432
|
+
}
|
|
433
|
+
function $getTableCellNodeFromLexicalNode(startingNode) {
|
|
434
|
+
const node = $findMatchingParent(startingNode, (n) => $isTableCellNode(n));
|
|
435
|
+
if ($isTableCellNode(node)) return node;
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
|
439
|
+
const node = $findMatchingParent(startingNode, (n) => $isTableRowNode(n));
|
|
440
|
+
if ($isTableRowNode(node)) return node;
|
|
441
|
+
throw new Error("Expected table cell to be inside of table row.");
|
|
442
|
+
}
|
|
443
|
+
function $getTableNodeFromLexicalNodeOrThrow(startingNode) {
|
|
444
|
+
const node = $findMatchingParent(startingNode, (n) => $isTableNode(n));
|
|
445
|
+
if ($isTableNode(node)) return node;
|
|
446
|
+
throw new Error("Expected table cell to be inside of table.");
|
|
447
|
+
}
|
|
448
|
+
function $getTableRowIndexFromTableCellNode(tableCellNode) {
|
|
449
|
+
const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);
|
|
450
|
+
return $getTableNodeFromLexicalNodeOrThrow(tableRowNode).getChildren().findIndex((n) => n.is(tableRowNode));
|
|
451
|
+
}
|
|
452
|
+
function $getTableColumnIndexFromTableCellNode(tableCellNode) {
|
|
453
|
+
return $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode).getChildren().findIndex((n) => n.is(tableCellNode));
|
|
454
|
+
}
|
|
455
|
+
function $getTableCellSiblingsFromTableCellNode(tableCellNode, table) {
|
|
456
|
+
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
|
|
457
|
+
const { x, y } = tableNode.getCordsFromCellNode(tableCellNode, table);
|
|
458
|
+
return {
|
|
459
|
+
above: tableNode.getCellNodeFromCords(x, y - 1, table),
|
|
460
|
+
below: tableNode.getCellNodeFromCords(x, y + 1, table),
|
|
461
|
+
left: tableNode.getCellNodeFromCords(x - 1, y, table),
|
|
462
|
+
right: tableNode.getCellNodeFromCords(x + 1, y, table)
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function $removeTableRowAtIndex(tableNode, indexToDelete) {
|
|
466
|
+
const tableRows = tableNode.getChildren();
|
|
467
|
+
if (indexToDelete >= tableRows.length || indexToDelete < 0) throw new Error("Expected table cell to be inside of table row.");
|
|
468
|
+
tableRows[indexToDelete].remove();
|
|
469
|
+
return tableNode;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* @deprecated This function does not support merged cells. Use {@link $insertTableRowAtSelection} or {@link $insertTableRowAtNode} instead.
|
|
473
|
+
*/
|
|
474
|
+
function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount, table) {
|
|
475
|
+
const tableRows = tableNode.getChildren();
|
|
476
|
+
if (targetIndex >= tableRows.length || targetIndex < 0) throw new Error("Table row target index out of range");
|
|
477
|
+
const targetRowNode = tableRows[targetIndex];
|
|
478
|
+
if ($isTableRowNode(targetRowNode)) for (let r = 0; r < rowCount; r++) {
|
|
479
|
+
const tableRowCells = targetRowNode.getChildren();
|
|
480
|
+
const tableColumnCount = tableRowCells.length;
|
|
481
|
+
const newTableRowNode = $createTableRowNode();
|
|
482
|
+
for (let c = 0; c < tableColumnCount; c++) {
|
|
483
|
+
const tableCellFromTargetRow = tableRowCells[c];
|
|
484
|
+
if (!$isTableCellNode(tableCellFromTargetRow)) formatDevErrorMessage(`Expected table cell`);
|
|
485
|
+
const { above, below } = $getTableCellSiblingsFromTableCellNode(tableCellFromTargetRow, table);
|
|
486
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
|
487
|
+
const width = above && above.getWidth() || below && below.getWidth() || void 0;
|
|
488
|
+
if (above && above.hasHeaderState(TableCellHeaderStates.COLUMN) || below && below.hasHeaderState(TableCellHeaderStates.COLUMN)) headerState |= TableCellHeaderStates.COLUMN;
|
|
489
|
+
const tableCellNode = $createTableCellNode(headerState, 1, width);
|
|
490
|
+
tableCellNode.append($createParagraphNode());
|
|
491
|
+
newTableRowNode.append(tableCellNode);
|
|
492
|
+
}
|
|
493
|
+
if (shouldInsertAfter) targetRowNode.insertAfter(newTableRowNode);
|
|
494
|
+
else targetRowNode.insertBefore(newTableRowNode);
|
|
495
|
+
}
|
|
496
|
+
else throw new Error("Row before insertion index does not exist.");
|
|
497
|
+
return tableNode;
|
|
498
|
+
}
|
|
499
|
+
const getHeaderState = (currentState, possibleState) => {
|
|
500
|
+
if (currentState === TableCellHeaderStates.BOTH || currentState === possibleState) return possibleState;
|
|
501
|
+
return TableCellHeaderStates.NO_STATUS;
|
|
502
|
+
};
|
|
503
|
+
/**
|
|
504
|
+
* Inserts a table row before or after the current focus cell node,
|
|
505
|
+
* taking into account any spans. If successful, returns the
|
|
506
|
+
* inserted table row node.
|
|
507
|
+
*/
|
|
508
|
+
function $insertTableRowAtSelection(insertAfter = true) {
|
|
509
|
+
const selection = $getSelection();
|
|
510
|
+
if (!($isRangeSelection(selection) || $isTableSelection(selection))) formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);
|
|
511
|
+
const anchor = selection.anchor.getNode();
|
|
512
|
+
const focus = selection.focus.getNode();
|
|
513
|
+
const [anchorCell] = $getNodeTriplet(anchor);
|
|
514
|
+
const [focusCell, , grid] = $getNodeTriplet(focus);
|
|
515
|
+
const [, focusCellMap, anchorCellMap] = $computeTableMap(grid, focusCell, anchorCell);
|
|
516
|
+
const { startRow: anchorStartRow } = anchorCellMap;
|
|
517
|
+
const { startRow: focusStartRow } = focusCellMap;
|
|
518
|
+
if (insertAfter) return $insertTableRowAtNode(anchorStartRow + anchorCell.__rowSpan > focusStartRow + focusCell.__rowSpan ? anchorCell : focusCell, true);
|
|
519
|
+
else return $insertTableRowAtNode(focusStartRow < anchorStartRow ? focusCell : anchorCell, false);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* @deprecated renamed to {@link $insertTableRowAtSelection}
|
|
523
|
+
*/
|
|
524
|
+
const $insertTableRow__EXPERIMENTAL = $insertTableRowAtSelection;
|
|
525
|
+
/**
|
|
526
|
+
* Inserts a table row before or after the given cell node,
|
|
527
|
+
* taking into account any spans. If successful, returns the
|
|
528
|
+
* inserted table row node.
|
|
529
|
+
*/
|
|
530
|
+
function $insertTableRowAtNode(cellNode, insertAfter = true) {
|
|
531
|
+
const [, , grid] = $getNodeTriplet(cellNode);
|
|
532
|
+
const [gridMap, cellMap] = $computeTableMap(grid, cellNode, cellNode);
|
|
533
|
+
const columnCount = gridMap[0].length;
|
|
534
|
+
const { startRow: cellStartRow } = cellMap;
|
|
535
|
+
let insertedRow = null;
|
|
536
|
+
if (insertAfter) {
|
|
537
|
+
const insertAfterEndRow = cellStartRow + cellNode.__rowSpan - 1;
|
|
538
|
+
const insertAfterEndRowMap = gridMap[insertAfterEndRow];
|
|
539
|
+
const newRow = $createTableRowNode();
|
|
540
|
+
for (let i = 0; i < columnCount; i++) {
|
|
541
|
+
const { cell, startRow } = insertAfterEndRowMap[i];
|
|
542
|
+
if (startRow + cell.__rowSpan - 1 <= insertAfterEndRow) {
|
|
543
|
+
const currentCellHeaderState = insertAfterEndRowMap[i].cell.__headerState;
|
|
544
|
+
const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.COLUMN);
|
|
545
|
+
newRow.append($createTableCellNode(headerState).append($createParagraphNode()));
|
|
546
|
+
} else cell.setRowSpan(cell.__rowSpan + 1);
|
|
547
|
+
}
|
|
548
|
+
const insertAfterEndRowNode = grid.getChildAtIndex(insertAfterEndRow);
|
|
549
|
+
if (!$isTableRowNode(insertAfterEndRowNode)) formatDevErrorMessage(`insertAfterEndRow is not a TableRowNode`);
|
|
550
|
+
insertAfterEndRowNode.insertAfter(newRow);
|
|
551
|
+
insertedRow = newRow;
|
|
552
|
+
} else {
|
|
553
|
+
const insertBeforeStartRow = cellStartRow;
|
|
554
|
+
const insertBeforeStartRowMap = gridMap[insertBeforeStartRow];
|
|
555
|
+
const newRow = $createTableRowNode();
|
|
556
|
+
for (let i = 0; i < columnCount; i++) {
|
|
557
|
+
const { cell, startRow } = insertBeforeStartRowMap[i];
|
|
558
|
+
if (startRow === insertBeforeStartRow) {
|
|
559
|
+
const currentCellHeaderState = insertBeforeStartRowMap[i].cell.__headerState;
|
|
560
|
+
const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.COLUMN);
|
|
561
|
+
newRow.append($createTableCellNode(headerState).append($createParagraphNode()));
|
|
562
|
+
} else cell.setRowSpan(cell.__rowSpan + 1);
|
|
563
|
+
}
|
|
564
|
+
const insertBeforeStartRowNode = grid.getChildAtIndex(insertBeforeStartRow);
|
|
565
|
+
if (!$isTableRowNode(insertBeforeStartRowNode)) formatDevErrorMessage(`insertBeforeStartRow is not a TableRowNode`);
|
|
566
|
+
insertBeforeStartRowNode.insertBefore(newRow);
|
|
567
|
+
insertedRow = newRow;
|
|
568
|
+
}
|
|
569
|
+
return insertedRow;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* @deprecated This function does not support merged cells. Use {@link $insertTableColumnAtSelection} or {@link $insertTableColumnAtNode} instead.
|
|
573
|
+
*/
|
|
574
|
+
function $insertTableColumn(tableNode, targetIndex, shouldInsertAfter = true, columnCount, table) {
|
|
575
|
+
const tableRows = tableNode.getChildren();
|
|
576
|
+
const tableCellsToBeInserted = [];
|
|
577
|
+
for (let r = 0; r < tableRows.length; r++) {
|
|
578
|
+
const currentTableRowNode = tableRows[r];
|
|
579
|
+
if ($isTableRowNode(currentTableRowNode)) for (let c = 0; c < columnCount; c++) {
|
|
580
|
+
const tableRowChildren = currentTableRowNode.getChildren();
|
|
581
|
+
if (targetIndex >= tableRowChildren.length || targetIndex < 0) throw new Error("Table column target index out of range");
|
|
582
|
+
const targetCell = tableRowChildren[targetIndex];
|
|
583
|
+
if (!$isTableCellNode(targetCell)) formatDevErrorMessage(`Expected table cell`);
|
|
584
|
+
const { left, right } = $getTableCellSiblingsFromTableCellNode(targetCell, table);
|
|
585
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
|
586
|
+
if (left && left.hasHeaderState(TableCellHeaderStates.ROW) || right && right.hasHeaderState(TableCellHeaderStates.ROW)) headerState |= TableCellHeaderStates.ROW;
|
|
587
|
+
const newTableCell = $createTableCellNode(headerState);
|
|
588
|
+
newTableCell.append($createParagraphNode());
|
|
589
|
+
tableCellsToBeInserted.push({
|
|
590
|
+
newTableCell,
|
|
591
|
+
targetCell
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
tableCellsToBeInserted.forEach(({ newTableCell, targetCell }) => {
|
|
596
|
+
if (shouldInsertAfter) targetCell.insertAfter(newTableCell);
|
|
597
|
+
else targetCell.insertBefore(newTableCell);
|
|
598
|
+
});
|
|
599
|
+
return tableNode;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Inserts a column before or after the current focus cell node,
|
|
603
|
+
* taking into account any spans. If successful, returns the
|
|
604
|
+
* first inserted cell node.
|
|
605
|
+
*/
|
|
606
|
+
function $insertTableColumnAtSelection(insertAfter = true) {
|
|
607
|
+
const selection = $getSelection();
|
|
608
|
+
if (!($isRangeSelection(selection) || $isTableSelection(selection))) formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);
|
|
609
|
+
const anchor = selection.anchor.getNode();
|
|
610
|
+
const focus = selection.focus.getNode();
|
|
611
|
+
const [anchorCell] = $getNodeTriplet(anchor);
|
|
612
|
+
const [focusCell, , grid] = $getNodeTriplet(focus);
|
|
613
|
+
const [, focusCellMap, anchorCellMap] = $computeTableMap(grid, focusCell, anchorCell);
|
|
614
|
+
const { startColumn: anchorStartColumn } = anchorCellMap;
|
|
615
|
+
const { startColumn: focusStartColumn } = focusCellMap;
|
|
616
|
+
if (insertAfter) return $insertTableColumnAtNode(anchorStartColumn + anchorCell.__colSpan > focusStartColumn + focusCell.__colSpan ? anchorCell : focusCell, true);
|
|
617
|
+
else return $insertTableColumnAtNode(focusStartColumn < anchorStartColumn ? focusCell : anchorCell, false);
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* @deprecated renamed to {@link $insertTableColumnAtSelection}
|
|
621
|
+
*/
|
|
622
|
+
const $insertTableColumn__EXPERIMENTAL = $insertTableColumnAtSelection;
|
|
623
|
+
/**
|
|
624
|
+
* Inserts a column before or after the given cell node,
|
|
625
|
+
* taking into account any spans. If successful, returns the
|
|
626
|
+
* first inserted cell node.
|
|
627
|
+
*/
|
|
628
|
+
function $insertTableColumnAtNode(cellNode, insertAfter = true, shouldSetSelection = true) {
|
|
629
|
+
const [, , grid] = $getNodeTriplet(cellNode);
|
|
630
|
+
const [gridMap, cellMap] = $computeTableMap(grid, cellNode, cellNode);
|
|
631
|
+
const rowCount = gridMap.length;
|
|
632
|
+
const { startColumn } = cellMap;
|
|
633
|
+
const insertAfterColumn = insertAfter ? startColumn + cellNode.__colSpan - 1 : startColumn - 1;
|
|
634
|
+
const gridFirstChild = grid.getFirstChild();
|
|
635
|
+
if (!$isTableRowNode(gridFirstChild)) formatDevErrorMessage(`Expected firstTable child to be a row`);
|
|
636
|
+
let firstInsertedCell = null;
|
|
637
|
+
function $createTableCellNodeForInsertTableColumn(headerState = TableCellHeaderStates.NO_STATUS) {
|
|
638
|
+
const cell = $createTableCellNode(headerState).append($createParagraphNode());
|
|
639
|
+
if (firstInsertedCell === null) firstInsertedCell = cell;
|
|
640
|
+
return cell;
|
|
641
|
+
}
|
|
642
|
+
let loopRow = gridFirstChild;
|
|
643
|
+
rowLoop: for (let i = 0; i < rowCount; i++) {
|
|
644
|
+
if (i !== 0) {
|
|
645
|
+
const currentRow = loopRow.getNextSibling();
|
|
646
|
+
if (!$isTableRowNode(currentRow)) formatDevErrorMessage(`Expected row nextSibling to be a row`);
|
|
647
|
+
loopRow = currentRow;
|
|
648
|
+
}
|
|
649
|
+
const rowMap = gridMap[i];
|
|
650
|
+
const currentCellHeaderState = rowMap[insertAfterColumn < 0 ? 0 : insertAfterColumn].cell.__headerState;
|
|
651
|
+
const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.ROW);
|
|
652
|
+
if (insertAfterColumn < 0) {
|
|
653
|
+
$insertFirst(loopRow, $createTableCellNodeForInsertTableColumn(headerState));
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
const { cell: currentCell, startColumn: currentStartColumn, startRow: currentStartRow } = rowMap[insertAfterColumn];
|
|
657
|
+
if (currentStartColumn + currentCell.__colSpan - 1 <= insertAfterColumn) {
|
|
658
|
+
let insertAfterCell = currentCell;
|
|
659
|
+
let insertAfterCellRowStart = currentStartRow;
|
|
660
|
+
let prevCellIndex = insertAfterColumn;
|
|
661
|
+
while (insertAfterCellRowStart !== i && insertAfterCell.__rowSpan > 1) {
|
|
662
|
+
prevCellIndex -= currentCell.__colSpan;
|
|
663
|
+
if (prevCellIndex >= 0) {
|
|
664
|
+
const { cell: cell_, startRow: startRow_ } = rowMap[prevCellIndex];
|
|
665
|
+
insertAfterCell = cell_;
|
|
666
|
+
insertAfterCellRowStart = startRow_;
|
|
667
|
+
} else {
|
|
668
|
+
loopRow.append($createTableCellNodeForInsertTableColumn(headerState));
|
|
669
|
+
continue rowLoop;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
insertAfterCell.insertAfter($createTableCellNodeForInsertTableColumn(headerState));
|
|
673
|
+
} else currentCell.setColSpan(currentCell.__colSpan + 1);
|
|
674
|
+
}
|
|
675
|
+
if (firstInsertedCell !== null && shouldSetSelection) $moveSelectionToCell(firstInsertedCell);
|
|
676
|
+
const colWidths = grid.getColWidths();
|
|
677
|
+
if (colWidths) {
|
|
678
|
+
const newColWidths = [...colWidths];
|
|
679
|
+
const columnIndex = insertAfterColumn < 0 ? 0 : insertAfterColumn;
|
|
680
|
+
const newWidth = newColWidths[columnIndex];
|
|
681
|
+
newColWidths.splice(columnIndex, 0, newWidth);
|
|
682
|
+
grid.setColWidths(newColWidths);
|
|
683
|
+
}
|
|
684
|
+
return firstInsertedCell;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* @deprecated This function does not support merged cells. Use {@link $deleteTableColumnAtSelection} instead.
|
|
688
|
+
*/
|
|
689
|
+
function $deleteTableColumn(tableNode, targetIndex) {
|
|
690
|
+
const tableRows = tableNode.getChildren();
|
|
691
|
+
for (let i = 0; i < tableRows.length; i++) {
|
|
692
|
+
const currentTableRowNode = tableRows[i];
|
|
693
|
+
if ($isTableRowNode(currentTableRowNode)) {
|
|
694
|
+
const tableRowChildren = currentTableRowNode.getChildren();
|
|
695
|
+
if (targetIndex >= tableRowChildren.length || targetIndex < 0) throw new Error("Table column target index out of range");
|
|
696
|
+
tableRowChildren[targetIndex].remove();
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return tableNode;
|
|
700
|
+
}
|
|
701
|
+
function $deleteTableRowAtSelection() {
|
|
702
|
+
const selection = $getSelection();
|
|
703
|
+
if (!($isRangeSelection(selection) || $isTableSelection(selection))) formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);
|
|
704
|
+
const [anchor, focus] = selection.isBackward() ? [selection.focus.getNode(), selection.anchor.getNode()] : [selection.anchor.getNode(), selection.focus.getNode()];
|
|
705
|
+
const [anchorCell, , grid] = $getNodeTriplet(anchor);
|
|
706
|
+
const [focusCell] = $getNodeTriplet(focus);
|
|
707
|
+
const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(grid, anchorCell, focusCell);
|
|
708
|
+
const { startRow: anchorStartRow } = anchorCellMap;
|
|
709
|
+
const { startRow: focusStartRow } = focusCellMap;
|
|
710
|
+
const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;
|
|
711
|
+
if (gridMap.length === focusEndRow - anchorStartRow + 1) {
|
|
712
|
+
grid.remove();
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
const columnCount = gridMap[0].length;
|
|
716
|
+
const nextRow = gridMap[focusEndRow + 1];
|
|
717
|
+
const nextRowNode = grid.getChildAtIndex(focusEndRow + 1);
|
|
718
|
+
for (let row = focusEndRow; row >= anchorStartRow; row--) {
|
|
719
|
+
for (let column = columnCount - 1; column >= 0; column--) {
|
|
720
|
+
const { cell, startRow: cellStartRow, startColumn: cellStartColumn } = gridMap[row][column];
|
|
721
|
+
if (cellStartColumn !== column) continue;
|
|
722
|
+
if (cellStartRow < anchorStartRow || cellStartRow + cell.__rowSpan - 1 > focusEndRow) {
|
|
723
|
+
const intersectionStart = Math.max(cellStartRow, anchorStartRow);
|
|
724
|
+
const intersectionEnd = Math.min(cell.__rowSpan + cellStartRow - 1, focusEndRow);
|
|
725
|
+
const overflowRowsCount = intersectionStart <= intersectionEnd ? intersectionEnd - intersectionStart + 1 : 0;
|
|
726
|
+
cell.setRowSpan(cell.__rowSpan - overflowRowsCount);
|
|
727
|
+
}
|
|
728
|
+
if (cellStartRow >= anchorStartRow && cellStartRow + cell.__rowSpan - 1 > focusEndRow && row === focusEndRow) {
|
|
729
|
+
if (!(nextRowNode !== null)) formatDevErrorMessage(`Expected nextRowNode not to be null`);
|
|
730
|
+
let insertAfterCell = null;
|
|
731
|
+
for (let columnIndex = 0; columnIndex < column; columnIndex++) {
|
|
732
|
+
const currentCellMap = nextRow[columnIndex];
|
|
733
|
+
const currentCell = currentCellMap.cell;
|
|
734
|
+
if (currentCellMap.startRow === row + 1) insertAfterCell = currentCell;
|
|
735
|
+
if (currentCell.__colSpan > 1) columnIndex += currentCell.__colSpan - 1;
|
|
736
|
+
}
|
|
737
|
+
if (insertAfterCell === null) $insertFirst(nextRowNode, cell);
|
|
738
|
+
else insertAfterCell.insertAfter(cell);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const rowNode = grid.getChildAtIndex(row);
|
|
742
|
+
if (!$isTableRowNode(rowNode)) formatDevErrorMessage(`Expected TableNode childAtIndex(${String(row)}) to be RowNode`);
|
|
743
|
+
rowNode.remove();
|
|
744
|
+
}
|
|
745
|
+
if (nextRow !== void 0) {
|
|
746
|
+
const { cell } = nextRow[0];
|
|
747
|
+
$moveSelectionToCell(cell);
|
|
748
|
+
} else {
|
|
749
|
+
const { cell } = gridMap[anchorStartRow - 1][0];
|
|
750
|
+
$moveSelectionToCell(cell);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* @deprecated renamed to {@link $deleteTableRowAtSelection}
|
|
755
|
+
*/
|
|
756
|
+
const $deleteTableRow__EXPERIMENTAL = $deleteTableRowAtSelection;
|
|
757
|
+
function $deleteTableColumnAtSelection() {
|
|
758
|
+
const selection = $getSelection();
|
|
759
|
+
if (!($isRangeSelection(selection) || $isTableSelection(selection))) formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);
|
|
760
|
+
const anchor = selection.anchor.getNode();
|
|
761
|
+
const focus = selection.focus.getNode();
|
|
762
|
+
const [anchorCell, , grid] = $getNodeTriplet(anchor);
|
|
763
|
+
const [focusCell] = $getNodeTriplet(focus);
|
|
764
|
+
const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(grid, anchorCell, focusCell);
|
|
765
|
+
const { startColumn: anchorStartColumn } = anchorCellMap;
|
|
766
|
+
const { startRow: focusStartRow, startColumn: focusStartColumn } = focusCellMap;
|
|
767
|
+
const startColumn = Math.min(anchorStartColumn, focusStartColumn);
|
|
768
|
+
const endColumn = Math.max(anchorStartColumn + anchorCell.__colSpan - 1, focusStartColumn + focusCell.__colSpan - 1);
|
|
769
|
+
const selectedColumnCount = endColumn - startColumn + 1;
|
|
770
|
+
if (gridMap[0].length === endColumn - startColumn + 1) {
|
|
771
|
+
grid.selectPrevious();
|
|
772
|
+
grid.remove();
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
const rowCount = gridMap.length;
|
|
776
|
+
for (let row = 0; row < rowCount; row++) for (let column = startColumn; column <= endColumn; column++) {
|
|
777
|
+
const { cell, startColumn: cellStartColumn } = gridMap[row][column];
|
|
778
|
+
if (cellStartColumn < startColumn) {
|
|
779
|
+
if (column === startColumn) {
|
|
780
|
+
const overflowLeft = startColumn - cellStartColumn;
|
|
781
|
+
cell.setColSpan(cell.__colSpan - Math.min(selectedColumnCount, cell.__colSpan - overflowLeft));
|
|
782
|
+
}
|
|
783
|
+
} else if (cellStartColumn + cell.__colSpan - 1 > endColumn) {
|
|
784
|
+
if (column === endColumn) {
|
|
785
|
+
const inSelectedArea = endColumn - cellStartColumn + 1;
|
|
786
|
+
cell.setColSpan(cell.__colSpan - inSelectedArea);
|
|
787
|
+
}
|
|
788
|
+
} else cell.remove();
|
|
789
|
+
}
|
|
790
|
+
const focusRowMap = gridMap[focusStartRow];
|
|
791
|
+
const nextColumn = anchorStartColumn > focusStartColumn ? focusRowMap[anchorStartColumn + anchorCell.__colSpan] : focusRowMap[focusStartColumn + focusCell.__colSpan];
|
|
792
|
+
if (nextColumn !== void 0) {
|
|
793
|
+
const { cell } = nextColumn;
|
|
794
|
+
$moveSelectionToCell(cell);
|
|
795
|
+
} else {
|
|
796
|
+
const { cell } = focusStartColumn < anchorStartColumn ? focusRowMap[focusStartColumn - 1] : focusRowMap[anchorStartColumn - 1];
|
|
797
|
+
$moveSelectionToCell(cell);
|
|
798
|
+
}
|
|
799
|
+
const colWidths = grid.getColWidths();
|
|
800
|
+
if (colWidths) {
|
|
801
|
+
const newColWidths = [...colWidths];
|
|
802
|
+
newColWidths.splice(startColumn, selectedColumnCount);
|
|
803
|
+
grid.setColWidths(newColWidths);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* @deprecated renamed to {@link $deleteTableColumnAtSelection}
|
|
808
|
+
*/
|
|
809
|
+
const $deleteTableColumn__EXPERIMENTAL = $deleteTableColumnAtSelection;
|
|
810
|
+
function $moveSelectionToCell(cell) {
|
|
811
|
+
const firstDescendant = cell.getFirstDescendant();
|
|
812
|
+
if (firstDescendant == null) cell.selectStart();
|
|
813
|
+
else firstDescendant.getParentOrThrow().selectStart();
|
|
814
|
+
}
|
|
815
|
+
function $insertFirst(parent, node) {
|
|
816
|
+
const firstChild = parent.getFirstChild();
|
|
817
|
+
if (firstChild !== null) firstChild.insertBefore(node);
|
|
818
|
+
else parent.append(node);
|
|
819
|
+
}
|
|
820
|
+
function $mergeCells(cellNodes) {
|
|
821
|
+
if (cellNodes.length === 0) return null;
|
|
822
|
+
const [gridMap] = $computeTableMapSkipCellCheck($getTableNodeFromLexicalNodeOrThrow(cellNodes[0]), null, null);
|
|
823
|
+
let minRow = Infinity;
|
|
824
|
+
let maxRow = -Infinity;
|
|
825
|
+
let minCol = Infinity;
|
|
826
|
+
let maxCol = -Infinity;
|
|
827
|
+
const processedCells = /* @__PURE__ */ new Set();
|
|
828
|
+
for (const row of gridMap) for (const mapCell of row) {
|
|
829
|
+
if (!mapCell || !mapCell.cell) continue;
|
|
830
|
+
const cellKey = mapCell.cell.getKey();
|
|
831
|
+
if (processedCells.has(cellKey)) continue;
|
|
832
|
+
if (cellNodes.some((cell) => cell.is(mapCell.cell))) {
|
|
833
|
+
processedCells.add(cellKey);
|
|
834
|
+
const cellStartRow = mapCell.startRow;
|
|
835
|
+
const cellStartCol = mapCell.startColumn;
|
|
836
|
+
const cellRowSpan = mapCell.cell.__rowSpan || 1;
|
|
837
|
+
const cellColSpan = mapCell.cell.__colSpan || 1;
|
|
838
|
+
minRow = Math.min(minRow, cellStartRow);
|
|
839
|
+
maxRow = Math.max(maxRow, cellStartRow + cellRowSpan - 1);
|
|
840
|
+
minCol = Math.min(minCol, cellStartCol);
|
|
841
|
+
maxCol = Math.max(maxCol, cellStartCol + cellColSpan - 1);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (minRow === Infinity || minCol === Infinity) return null;
|
|
845
|
+
const totalRowSpan = maxRow - minRow + 1;
|
|
846
|
+
const totalColSpan = maxCol - minCol + 1;
|
|
847
|
+
const targetCellMap = gridMap[minRow][minCol];
|
|
848
|
+
if (!targetCellMap.cell) return null;
|
|
849
|
+
const targetCell = targetCellMap.cell;
|
|
850
|
+
targetCell.setColSpan(totalColSpan);
|
|
851
|
+
targetCell.setRowSpan(totalRowSpan);
|
|
852
|
+
const seenCells = new Set([targetCell.getKey()]);
|
|
853
|
+
for (let row = minRow; row <= maxRow; row++) for (let col = minCol; col <= maxCol; col++) {
|
|
854
|
+
const mapCell = gridMap[row][col];
|
|
855
|
+
if (!mapCell.cell) continue;
|
|
856
|
+
const currentCell = mapCell.cell;
|
|
857
|
+
const key = currentCell.getKey();
|
|
858
|
+
if (!seenCells.has(key)) {
|
|
859
|
+
seenCells.add(key);
|
|
860
|
+
if (!$cellContainsEmptyParagraph(currentCell)) targetCell.append(...currentCell.getChildren());
|
|
861
|
+
currentCell.remove();
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
if (targetCell.getChildrenSize() === 0) targetCell.append($createParagraphNode());
|
|
865
|
+
return targetCell;
|
|
866
|
+
}
|
|
867
|
+
function $cellContainsEmptyParagraph(cell) {
|
|
868
|
+
if (cell.getChildrenSize() !== 1) return false;
|
|
869
|
+
const firstChild = cell.getFirstChildOrThrow();
|
|
870
|
+
if (!$isParagraphNode(firstChild) || !firstChild.isEmpty()) return false;
|
|
871
|
+
return true;
|
|
872
|
+
}
|
|
873
|
+
function $unmergeCell() {
|
|
874
|
+
const selection = $getSelection();
|
|
875
|
+
if (!($isRangeSelection(selection) || $isTableSelection(selection))) formatDevErrorMessage(`Expected a RangeSelection or TableSelection`);
|
|
876
|
+
const cellNode = $findMatchingParent(selection.anchor.getNode(), $isTableCellNode);
|
|
877
|
+
if (!$isTableCellNode(cellNode)) formatDevErrorMessage(`Expected to find a parent TableCellNode`);
|
|
878
|
+
return $unmergeCellNode(cellNode);
|
|
879
|
+
}
|
|
880
|
+
function $unmergeCellNode(cellNode) {
|
|
881
|
+
const [cell, row, grid] = $getNodeTriplet(cellNode);
|
|
882
|
+
const colSpan = cell.__colSpan;
|
|
883
|
+
const rowSpan = cell.__rowSpan;
|
|
884
|
+
if (colSpan === 1 && rowSpan === 1) return;
|
|
885
|
+
const [map, cellMap] = $computeTableMap(grid, cell, cell);
|
|
886
|
+
const { startColumn, startRow } = cellMap;
|
|
887
|
+
const baseColStyle = cell.__headerState & TableCellHeaderStates.COLUMN;
|
|
888
|
+
const colStyles = Array.from({ length: colSpan }, (_v, i) => {
|
|
889
|
+
let colStyle = baseColStyle;
|
|
890
|
+
for (let rowIdx = 0; colStyle !== 0 && rowIdx < map.length; rowIdx++) colStyle &= map[rowIdx][i + startColumn].cell.__headerState;
|
|
891
|
+
return colStyle;
|
|
892
|
+
});
|
|
893
|
+
const baseRowStyle = cell.__headerState & TableCellHeaderStates.ROW;
|
|
894
|
+
const rowStyles = Array.from({ length: rowSpan }, (_v, i) => {
|
|
895
|
+
let rowStyle = baseRowStyle;
|
|
896
|
+
for (let colIdx = 0; rowStyle !== 0 && colIdx < map[0].length; colIdx++) rowStyle &= map[i + startRow][colIdx].cell.__headerState;
|
|
897
|
+
return rowStyle;
|
|
898
|
+
});
|
|
899
|
+
if (colSpan > 1) {
|
|
900
|
+
for (let i = 1; i < colSpan; i++) cell.insertAfter($createTableCellNode(colStyles[i] | rowStyles[0]).append($createParagraphNode()));
|
|
901
|
+
cell.setColSpan(1);
|
|
902
|
+
}
|
|
903
|
+
if (rowSpan > 1) {
|
|
904
|
+
let currentRowNode;
|
|
905
|
+
for (let i = 1; i < rowSpan; i++) {
|
|
906
|
+
const currentRow = startRow + i;
|
|
907
|
+
const currentRowMap = map[currentRow];
|
|
908
|
+
currentRowNode = (currentRowNode || row).getNextSibling();
|
|
909
|
+
if (!$isTableRowNode(currentRowNode)) formatDevErrorMessage(`Expected row next sibling to be a row`);
|
|
910
|
+
let insertAfterCell = null;
|
|
911
|
+
for (let column = 0; column < startColumn; column++) {
|
|
912
|
+
const currentCellMap = currentRowMap[column];
|
|
913
|
+
const currentCell = currentCellMap.cell;
|
|
914
|
+
if (currentCellMap.startRow === currentRow) insertAfterCell = currentCell;
|
|
915
|
+
if (currentCell.__colSpan > 1) column += currentCell.__colSpan - 1;
|
|
916
|
+
}
|
|
917
|
+
if (insertAfterCell === null) for (let j = colSpan - 1; j >= 0; j--) $insertFirst(currentRowNode, $createTableCellNode(colStyles[j] | rowStyles[i]).append($createParagraphNode()));
|
|
918
|
+
else for (let j = colSpan - 1; j >= 0; j--) insertAfterCell.insertAfter($createTableCellNode(colStyles[j] | rowStyles[i]).append($createParagraphNode()));
|
|
919
|
+
}
|
|
920
|
+
cell.setRowSpan(1);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
function $computeTableMap(tableNode, cellA, cellB) {
|
|
924
|
+
const [tableMap, cellAValue, cellBValue] = $computeTableMapSkipCellCheck(tableNode, cellA, cellB);
|
|
925
|
+
if (!(cellAValue !== null)) formatDevErrorMessage(`Anchor not found in Table`);
|
|
926
|
+
if (!(cellBValue !== null)) formatDevErrorMessage(`Focus not found in Table`);
|
|
927
|
+
return [
|
|
928
|
+
tableMap,
|
|
929
|
+
cellAValue,
|
|
930
|
+
cellBValue
|
|
931
|
+
];
|
|
932
|
+
}
|
|
933
|
+
function $computeTableMapSkipCellCheck(tableNode, cellA, cellB) {
|
|
934
|
+
const tableMap = [];
|
|
935
|
+
let cellAValue = null;
|
|
936
|
+
let cellBValue = null;
|
|
937
|
+
function getMapRow(i) {
|
|
938
|
+
let row = tableMap[i];
|
|
939
|
+
if (row === void 0) tableMap[i] = row = [];
|
|
940
|
+
return row;
|
|
941
|
+
}
|
|
942
|
+
const gridChildren = tableNode.getChildren();
|
|
943
|
+
for (let rowIdx = 0; rowIdx < gridChildren.length; rowIdx++) {
|
|
944
|
+
const row = gridChildren[rowIdx];
|
|
945
|
+
if (!$isTableRowNode(row)) formatDevErrorMessage(`Expected TableNode children to be TableRowNode`);
|
|
946
|
+
const startMapRow = getMapRow(rowIdx);
|
|
947
|
+
for (let cell = row.getFirstChild(), colIdx = 0; cell != null; cell = cell.getNextSibling()) {
|
|
948
|
+
if (!$isTableCellNode(cell)) formatDevErrorMessage(`Expected TableRowNode children to be TableCellNode`);
|
|
949
|
+
while (startMapRow[colIdx] !== void 0) colIdx++;
|
|
950
|
+
const value = {
|
|
951
|
+
cell,
|
|
952
|
+
startColumn: colIdx,
|
|
953
|
+
startRow: rowIdx
|
|
954
|
+
};
|
|
955
|
+
const { __rowSpan: rowSpan, __colSpan: colSpan } = cell;
|
|
956
|
+
for (let j = 0; j < rowSpan; j++) {
|
|
957
|
+
if (rowIdx + j >= gridChildren.length) break;
|
|
958
|
+
const mapRow = getMapRow(rowIdx + j);
|
|
959
|
+
for (let i = 0; i < colSpan; i++) mapRow[colIdx + i] = value;
|
|
960
|
+
}
|
|
961
|
+
if (cellA !== null && cellAValue === null && cellA.is(cell)) cellAValue = value;
|
|
962
|
+
if (cellB !== null && cellBValue === null && cellB.is(cell)) cellBValue = value;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return [
|
|
966
|
+
tableMap,
|
|
967
|
+
cellAValue,
|
|
968
|
+
cellBValue
|
|
969
|
+
];
|
|
970
|
+
}
|
|
971
|
+
function $getNodeTriplet(source) {
|
|
972
|
+
let cell;
|
|
973
|
+
if (source instanceof TableCellNode) cell = source;
|
|
974
|
+
else if ("__type" in source) {
|
|
975
|
+
const cell_ = $findMatchingParent(source, $isTableCellNode);
|
|
976
|
+
if (!$isTableCellNode(cell_)) formatDevErrorMessage(`Expected to find a parent TableCellNode`);
|
|
977
|
+
cell = cell_;
|
|
978
|
+
} else {
|
|
979
|
+
const cell_ = $findMatchingParent(source.getNode(), $isTableCellNode);
|
|
980
|
+
if (!$isTableCellNode(cell_)) formatDevErrorMessage(`Expected to find a parent TableCellNode`);
|
|
981
|
+
cell = cell_;
|
|
982
|
+
}
|
|
983
|
+
const row = cell.getParent();
|
|
984
|
+
if (!$isTableRowNode(row)) formatDevErrorMessage(`Expected TableCellNode to have a parent TableRowNode`);
|
|
985
|
+
const grid = row.getParent();
|
|
986
|
+
if (!$isTableNode(grid)) formatDevErrorMessage(`Expected TableRowNode to have a parent TableNode`);
|
|
987
|
+
return [
|
|
988
|
+
cell,
|
|
989
|
+
row,
|
|
990
|
+
grid
|
|
991
|
+
];
|
|
992
|
+
}
|
|
993
|
+
function $computeTableCellRectSpans(map, boundary) {
|
|
994
|
+
const { minColumn, maxColumn, minRow, maxRow } = boundary;
|
|
995
|
+
let topSpan = 1;
|
|
996
|
+
let leftSpan = 1;
|
|
997
|
+
let rightSpan = 1;
|
|
998
|
+
let bottomSpan = 1;
|
|
999
|
+
const topRow = map[minRow];
|
|
1000
|
+
const bottomRow = map[maxRow];
|
|
1001
|
+
for (let col = minColumn; col <= maxColumn; col++) {
|
|
1002
|
+
topSpan = Math.max(topSpan, topRow[col].cell.__rowSpan);
|
|
1003
|
+
bottomSpan = Math.max(bottomSpan, bottomRow[col].cell.__rowSpan);
|
|
1004
|
+
}
|
|
1005
|
+
for (let row = minRow; row <= maxRow; row++) {
|
|
1006
|
+
leftSpan = Math.max(leftSpan, map[row][minColumn].cell.__colSpan);
|
|
1007
|
+
rightSpan = Math.max(rightSpan, map[row][maxColumn].cell.__colSpan);
|
|
1008
|
+
}
|
|
1009
|
+
return {
|
|
1010
|
+
bottomSpan,
|
|
1011
|
+
leftSpan,
|
|
1012
|
+
rightSpan,
|
|
1013
|
+
topSpan
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
function $computeTableCellRectBoundary(map, cellAMap, cellBMap) {
|
|
1017
|
+
let minColumn = Math.min(cellAMap.startColumn, cellBMap.startColumn);
|
|
1018
|
+
let minRow = Math.min(cellAMap.startRow, cellBMap.startRow);
|
|
1019
|
+
let maxColumn = Math.max(cellAMap.startColumn + cellAMap.cell.__colSpan - 1, cellBMap.startColumn + cellBMap.cell.__colSpan - 1);
|
|
1020
|
+
let maxRow = Math.max(cellAMap.startRow + cellAMap.cell.__rowSpan - 1, cellBMap.startRow + cellBMap.cell.__rowSpan - 1);
|
|
1021
|
+
let hasChanges;
|
|
1022
|
+
do {
|
|
1023
|
+
hasChanges = false;
|
|
1024
|
+
for (let row = 0; row < map.length; row++) for (let col = 0; col < map[0].length; col++) {
|
|
1025
|
+
const cell = map[row][col];
|
|
1026
|
+
if (!cell) continue;
|
|
1027
|
+
const cellEndCol = cell.startColumn + cell.cell.__colSpan - 1;
|
|
1028
|
+
const cellEndRow = cell.startRow + cell.cell.__rowSpan - 1;
|
|
1029
|
+
const intersectsHorizontally = cell.startColumn <= maxColumn && cellEndCol >= minColumn;
|
|
1030
|
+
const intersectsVertically = cell.startRow <= maxRow && cellEndRow >= minRow;
|
|
1031
|
+
if (intersectsHorizontally && intersectsVertically) {
|
|
1032
|
+
const newMinColumn = Math.min(minColumn, cell.startColumn);
|
|
1033
|
+
const newMaxColumn = Math.max(maxColumn, cellEndCol);
|
|
1034
|
+
const newMinRow = Math.min(minRow, cell.startRow);
|
|
1035
|
+
const newMaxRow = Math.max(maxRow, cellEndRow);
|
|
1036
|
+
if (newMinColumn !== minColumn || newMaxColumn !== maxColumn || newMinRow !== minRow || newMaxRow !== maxRow) {
|
|
1037
|
+
minColumn = newMinColumn;
|
|
1038
|
+
maxColumn = newMaxColumn;
|
|
1039
|
+
minRow = newMinRow;
|
|
1040
|
+
maxRow = newMaxRow;
|
|
1041
|
+
hasChanges = true;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
} while (hasChanges);
|
|
1046
|
+
return {
|
|
1047
|
+
maxColumn,
|
|
1048
|
+
maxRow,
|
|
1049
|
+
minColumn,
|
|
1050
|
+
minRow
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Checks if the table does not have any merged cells.
|
|
1055
|
+
*
|
|
1056
|
+
* @param table Table to check for if it has any merged cells.
|
|
1057
|
+
* @returns True if the table does not have any merged cells, false otherwise.
|
|
1058
|
+
*/
|
|
1059
|
+
function $isSimpleTable(table) {
|
|
1060
|
+
const rows = table.getChildren();
|
|
1061
|
+
let columns = null;
|
|
1062
|
+
for (const row of rows) {
|
|
1063
|
+
if (!$isTableRowNode(row)) return false;
|
|
1064
|
+
if (columns === null) columns = row.getChildrenSize();
|
|
1065
|
+
if (row.getChildrenSize() !== columns) return false;
|
|
1066
|
+
const cells = row.getChildren();
|
|
1067
|
+
for (const cell of cells) if (!$isTableCellNode(cell) || cell.getRowSpan() !== 1 || cell.getColSpan() !== 1) return false;
|
|
1068
|
+
}
|
|
1069
|
+
return (columns || 0) > 0;
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Moves a column from one position to another within a simple (non-merged) table.
|
|
1073
|
+
*
|
|
1074
|
+
* @param tableNode The table node to modify.
|
|
1075
|
+
* @param originColumn The index of the column to move.
|
|
1076
|
+
* @param targetColumn The index to move the column to.
|
|
1077
|
+
*/
|
|
1078
|
+
function $moveTableColumn(tableNode, originColumn, targetColumn) {
|
|
1079
|
+
if (originColumn === targetColumn) return;
|
|
1080
|
+
const columnCount = tableNode.getColumnCount();
|
|
1081
|
+
if (originColumn < 0 || originColumn >= columnCount || targetColumn < 0 || targetColumn >= columnCount) return;
|
|
1082
|
+
if (!$isSimpleTable(tableNode)) return;
|
|
1083
|
+
tableNode.getChildren().filter($isTableRowNode).forEach((row) => {
|
|
1084
|
+
const cells = row.getChildren();
|
|
1085
|
+
const [moved] = cells.splice(originColumn, 1);
|
|
1086
|
+
cells.splice(targetColumn, 0, moved);
|
|
1087
|
+
row.splice(0, cells.length, cells);
|
|
1088
|
+
});
|
|
1089
|
+
const colWidths = tableNode.getColWidths();
|
|
1090
|
+
if (colWidths && colWidths.length === columnCount) {
|
|
1091
|
+
const newWidths = [...colWidths];
|
|
1092
|
+
const [movedWidth] = newWidths.splice(originColumn, 1);
|
|
1093
|
+
newWidths.splice(targetColumn, 0, movedWidth);
|
|
1094
|
+
tableNode.setColWidths(newWidths);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
function $getTableCellNodeRect(tableCellNode) {
|
|
1098
|
+
const [cellNode, , gridNode] = $getNodeTriplet(tableCellNode);
|
|
1099
|
+
const rows = gridNode.getChildren();
|
|
1100
|
+
const rowCount = rows.length;
|
|
1101
|
+
const columnCount = rows[0].getChildren().length;
|
|
1102
|
+
const cellMatrix = new Array(rowCount);
|
|
1103
|
+
for (let i = 0; i < rowCount; i++) cellMatrix[i] = new Array(columnCount);
|
|
1104
|
+
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
1105
|
+
const cells = rows[rowIndex].getChildren();
|
|
1106
|
+
let columnIndex = 0;
|
|
1107
|
+
for (let cellIndex = 0; cellIndex < cells.length; cellIndex++) {
|
|
1108
|
+
while (cellMatrix[rowIndex][columnIndex]) columnIndex++;
|
|
1109
|
+
const cell = cells[cellIndex];
|
|
1110
|
+
const rowSpan = cell.__rowSpan || 1;
|
|
1111
|
+
const colSpan = cell.__colSpan || 1;
|
|
1112
|
+
for (let i = 0; i < rowSpan; i++) for (let j = 0; j < colSpan; j++) cellMatrix[rowIndex + i][columnIndex + j] = cell;
|
|
1113
|
+
if (cellNode === cell) return {
|
|
1114
|
+
colSpan,
|
|
1115
|
+
columnIndex,
|
|
1116
|
+
rowIndex,
|
|
1117
|
+
rowSpan
|
|
1118
|
+
};
|
|
1119
|
+
columnIndex += colSpan;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1124
|
+
function $getCellNodes(tableSelection) {
|
|
1125
|
+
const [[anchorNode, anchorCell, anchorRow, anchorTable], [focusNode, focusCell, focusRow, focusTable]] = ["anchor", "focus"].map((k) => {
|
|
1126
|
+
const node = tableSelection[k].getNode();
|
|
1127
|
+
const cellNode = $findMatchingParent(node, $isTableCellNode);
|
|
1128
|
+
if (!$isTableCellNode(cellNode)) formatDevErrorMessage(`Expected TableSelection ${k} to be (or a child of) TableCellNode, got key ${node.getKey()} of type ${node.getType()}`);
|
|
1129
|
+
const rowNode = cellNode.getParent();
|
|
1130
|
+
if (!$isTableRowNode(rowNode)) formatDevErrorMessage(`Expected TableSelection ${k} cell parent to be a TableRowNode`);
|
|
1131
|
+
const tableNode = rowNode.getParent();
|
|
1132
|
+
if (!$isTableNode(tableNode)) formatDevErrorMessage(`Expected TableSelection ${k} row parent to be a TableNode`);
|
|
1133
|
+
return [
|
|
1134
|
+
node,
|
|
1135
|
+
cellNode,
|
|
1136
|
+
rowNode,
|
|
1137
|
+
tableNode
|
|
1138
|
+
];
|
|
1139
|
+
});
|
|
1140
|
+
if (!anchorTable.is(focusTable)) formatDevErrorMessage(`Expected TableSelection anchor and focus to be in the same table`);
|
|
1141
|
+
return {
|
|
1142
|
+
anchorCell,
|
|
1143
|
+
anchorNode,
|
|
1144
|
+
anchorRow,
|
|
1145
|
+
anchorTable,
|
|
1146
|
+
focusCell,
|
|
1147
|
+
focusNode,
|
|
1148
|
+
focusRow,
|
|
1149
|
+
focusTable
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
var TableSelection = class TableSelection {
|
|
1153
|
+
tableKey;
|
|
1154
|
+
anchor;
|
|
1155
|
+
focus;
|
|
1156
|
+
_cachedNodes;
|
|
1157
|
+
dirty;
|
|
1158
|
+
constructor(tableKey, anchor, focus) {
|
|
1159
|
+
this.anchor = anchor;
|
|
1160
|
+
this.focus = focus;
|
|
1161
|
+
anchor._selection = this;
|
|
1162
|
+
focus._selection = this;
|
|
1163
|
+
this._cachedNodes = null;
|
|
1164
|
+
this.dirty = false;
|
|
1165
|
+
this.tableKey = tableKey;
|
|
1166
|
+
}
|
|
1167
|
+
getStartEndPoints() {
|
|
1168
|
+
return [this.anchor, this.focus];
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* {@link $createTableSelection} unfortunately makes it very easy to create
|
|
1172
|
+
* nonsense selections, so we have a method to see if the selection probably
|
|
1173
|
+
* makes sense.
|
|
1174
|
+
*
|
|
1175
|
+
* @returns true if the TableSelection is (probably) valid
|
|
1176
|
+
*/
|
|
1177
|
+
isValid() {
|
|
1178
|
+
if (this.tableKey === "root" || this.anchor.key === "root" || this.anchor.type !== "element" || this.focus.key === "root" || this.focus.type !== "element") return false;
|
|
1179
|
+
const tableNode = $getNodeByKey(this.tableKey);
|
|
1180
|
+
const anchorNode = $getNodeByKey(this.anchor.key);
|
|
1181
|
+
const focusNode = $getNodeByKey(this.focus.key);
|
|
1182
|
+
return tableNode !== null && anchorNode !== null && focusNode !== null;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Returns whether the Selection is "backwards", meaning the focus
|
|
1186
|
+
* logically precedes the anchor in the EditorState.
|
|
1187
|
+
* @returns true if the Selection is backwards, false otherwise.
|
|
1188
|
+
*/
|
|
1189
|
+
isBackward() {
|
|
1190
|
+
return this.focus.isBefore(this.anchor);
|
|
1191
|
+
}
|
|
1192
|
+
getCachedNodes() {
|
|
1193
|
+
return this._cachedNodes;
|
|
1194
|
+
}
|
|
1195
|
+
setCachedNodes(nodes) {
|
|
1196
|
+
this._cachedNodes = nodes;
|
|
1197
|
+
}
|
|
1198
|
+
is(selection) {
|
|
1199
|
+
return $isTableSelection(selection) && this.tableKey === selection.tableKey && this.anchor.is(selection.anchor) && this.focus.is(selection.focus);
|
|
1200
|
+
}
|
|
1201
|
+
set(tableKey, anchorCellKey, focusCellKey) {
|
|
1202
|
+
this.dirty = this.dirty || tableKey !== this.tableKey || anchorCellKey !== this.anchor.key || focusCellKey !== this.focus.key;
|
|
1203
|
+
this.tableKey = tableKey;
|
|
1204
|
+
this.anchor.key = anchorCellKey;
|
|
1205
|
+
this.focus.key = focusCellKey;
|
|
1206
|
+
this._cachedNodes = null;
|
|
1207
|
+
}
|
|
1208
|
+
clone() {
|
|
1209
|
+
return new TableSelection(this.tableKey, $createPoint(this.anchor.key, this.anchor.offset, this.anchor.type), $createPoint(this.focus.key, this.focus.offset, this.focus.type));
|
|
1210
|
+
}
|
|
1211
|
+
isCollapsed() {
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
extract() {
|
|
1215
|
+
return this.getNodes();
|
|
1216
|
+
}
|
|
1217
|
+
insertRawText(text) {}
|
|
1218
|
+
insertText() {}
|
|
1219
|
+
/**
|
|
1220
|
+
* Returns whether the provided TextFormatType is present on the Selection.
|
|
1221
|
+
* This will be true if any paragraph in table cells has the specified format.
|
|
1222
|
+
*
|
|
1223
|
+
* @param type the TextFormatType to check for.
|
|
1224
|
+
* @returns true if the provided format is currently toggled on on the Selection, false otherwise.
|
|
1225
|
+
*/
|
|
1226
|
+
hasFormat(type) {
|
|
1227
|
+
let format = 0;
|
|
1228
|
+
this.getNodes().filter($isTableCellNode).forEach((cellNode) => {
|
|
1229
|
+
const paragraph = cellNode.getFirstChild();
|
|
1230
|
+
if ($isParagraphNode(paragraph)) format |= paragraph.getTextFormat();
|
|
1231
|
+
});
|
|
1232
|
+
const formatFlag = TEXT_TYPE_TO_FORMAT[type];
|
|
1233
|
+
return (format & formatFlag) !== 0;
|
|
1234
|
+
}
|
|
1235
|
+
insertNodes(nodes) {
|
|
1236
|
+
const focusNode = this.focus.getNode();
|
|
1237
|
+
if (!$isElementNode(focusNode)) formatDevErrorMessage(`Expected TableSelection focus to be an ElementNode`);
|
|
1238
|
+
$normalizeSelection__EXPERIMENTAL(focusNode.select(0, focusNode.getChildrenSize())).insertNodes(nodes);
|
|
1239
|
+
}
|
|
1240
|
+
getShape() {
|
|
1241
|
+
const { anchorCell, focusCell } = $getCellNodes(this);
|
|
1242
|
+
const anchorCellNodeRect = $getTableCellNodeRect(anchorCell);
|
|
1243
|
+
if (!(anchorCellNodeRect !== null)) formatDevErrorMessage(`getCellRect: expected to find AnchorNode`);
|
|
1244
|
+
const focusCellNodeRect = $getTableCellNodeRect(focusCell);
|
|
1245
|
+
if (!(focusCellNodeRect !== null)) formatDevErrorMessage(`getCellRect: expected to find focusCellNode`);
|
|
1246
|
+
const startX = Math.min(anchorCellNodeRect.columnIndex, focusCellNodeRect.columnIndex);
|
|
1247
|
+
const stopX = Math.max(anchorCellNodeRect.columnIndex + anchorCellNodeRect.colSpan - 1, focusCellNodeRect.columnIndex + focusCellNodeRect.colSpan - 1);
|
|
1248
|
+
const startY = Math.min(anchorCellNodeRect.rowIndex, focusCellNodeRect.rowIndex);
|
|
1249
|
+
const stopY = Math.max(anchorCellNodeRect.rowIndex + anchorCellNodeRect.rowSpan - 1, focusCellNodeRect.rowIndex + focusCellNodeRect.rowSpan - 1);
|
|
1250
|
+
return {
|
|
1251
|
+
fromX: Math.min(startX, stopX),
|
|
1252
|
+
fromY: Math.min(startY, stopY),
|
|
1253
|
+
toX: Math.max(startX, stopX),
|
|
1254
|
+
toY: Math.max(startY, stopY)
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
getNodes() {
|
|
1258
|
+
if (!this.isValid()) return [];
|
|
1259
|
+
const cachedNodes = this._cachedNodes;
|
|
1260
|
+
if (cachedNodes !== null) return cachedNodes;
|
|
1261
|
+
const { anchorTable: tableNode, anchorCell, focusCell } = $getCellNodes(this);
|
|
1262
|
+
const focusCellGrid = focusCell.getParents()[1];
|
|
1263
|
+
if (focusCellGrid !== tableNode) {
|
|
1264
|
+
if (!tableNode.isParentOf(focusCell)) {
|
|
1265
|
+
const gridParent = tableNode.getParent();
|
|
1266
|
+
if (!(gridParent != null)) formatDevErrorMessage(`Expected gridParent to have a parent`);
|
|
1267
|
+
this.set(this.tableKey, gridParent.getKey(), focusCell.getKey());
|
|
1268
|
+
} else {
|
|
1269
|
+
const focusCellParent = focusCellGrid.getParent();
|
|
1270
|
+
if (!(focusCellParent != null)) formatDevErrorMessage(`Expected focusCellParent to have a parent`);
|
|
1271
|
+
this.set(this.tableKey, focusCell.getKey(), focusCellParent.getKey());
|
|
1272
|
+
}
|
|
1273
|
+
return this.getNodes();
|
|
1274
|
+
}
|
|
1275
|
+
const [map, cellAMap, cellBMap] = $computeTableMap(tableNode, anchorCell, focusCell);
|
|
1276
|
+
const { minColumn, maxColumn, minRow, maxRow } = $computeTableCellRectBoundary(map, cellAMap, cellBMap);
|
|
1277
|
+
const nodeMap = new Map([[tableNode.getKey(), tableNode]]);
|
|
1278
|
+
let lastRow = null;
|
|
1279
|
+
for (let i = minRow; i <= maxRow; i++) for (let j = minColumn; j <= maxColumn; j++) {
|
|
1280
|
+
const { cell } = map[i][j];
|
|
1281
|
+
const currentRow = cell.getParent();
|
|
1282
|
+
if (!$isTableRowNode(currentRow)) formatDevErrorMessage(`Expected TableCellNode parent to be a TableRowNode`);
|
|
1283
|
+
if (currentRow !== lastRow) {
|
|
1284
|
+
nodeMap.set(currentRow.getKey(), currentRow);
|
|
1285
|
+
lastRow = currentRow;
|
|
1286
|
+
}
|
|
1287
|
+
if (!nodeMap.has(cell.getKey())) $visitRecursively(cell, (childNode) => {
|
|
1288
|
+
nodeMap.set(childNode.getKey(), childNode);
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
const nodes = Array.from(nodeMap.values());
|
|
1292
|
+
if (!isCurrentlyReadOnlyMode()) this._cachedNodes = nodes;
|
|
1293
|
+
return nodes;
|
|
1294
|
+
}
|
|
1295
|
+
getTextContent() {
|
|
1296
|
+
const nodes = this.getNodes().filter((node) => $isTableCellNode(node));
|
|
1297
|
+
let textContent = "";
|
|
1298
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
1299
|
+
const node = nodes[i];
|
|
1300
|
+
const row = node.__parent;
|
|
1301
|
+
const nextRow = (nodes[i + 1] || {}).__parent;
|
|
1302
|
+
textContent += node.getTextContent() + (nextRow !== row ? "\n" : " ");
|
|
1303
|
+
}
|
|
1304
|
+
return textContent;
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
function $isTableSelection(x) {
|
|
1308
|
+
return x instanceof TableSelection;
|
|
1309
|
+
}
|
|
1310
|
+
function $createTableSelection() {
|
|
1311
|
+
return new TableSelection("root", $createPoint("root", 0, "element"), $createPoint("root", 0, "element"));
|
|
1312
|
+
}
|
|
1313
|
+
function $createTableSelectionFrom(tableNode, anchorCell, focusCell) {
|
|
1314
|
+
const tableNodeKey = tableNode.getKey();
|
|
1315
|
+
const anchorCellKey = anchorCell.getKey();
|
|
1316
|
+
const focusCellKey = focusCell.getKey();
|
|
1317
|
+
if (!tableNode.isAttached()) formatDevErrorMessage(`$createTableSelectionFrom: tableNode ${tableNodeKey} is not attached`);
|
|
1318
|
+
if (!tableNode.is($findTableNode(anchorCell))) formatDevErrorMessage(`$createTableSelectionFrom: anchorCell ${anchorCellKey} is not in table ${tableNodeKey}`);
|
|
1319
|
+
if (!tableNode.is($findTableNode(focusCell))) formatDevErrorMessage(`$createTableSelectionFrom: focusCell ${focusCellKey} is not in table ${tableNodeKey}`);
|
|
1320
|
+
const prevSelection = $getSelection();
|
|
1321
|
+
const nextSelection = $isTableSelection(prevSelection) ? prevSelection.clone() : $createTableSelection();
|
|
1322
|
+
nextSelection.set(tableNode.getKey(), anchorCell.getKey(), focusCell.getKey());
|
|
1323
|
+
return nextSelection;
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Depth first visitor
|
|
1327
|
+
* @param node The starting node
|
|
1328
|
+
* @param $visit The function to call for each node. If the function returns false, then children of this node will not be explored
|
|
1329
|
+
*/
|
|
1330
|
+
function $visitRecursively(node, $visit) {
|
|
1331
|
+
const stack = [[node]];
|
|
1332
|
+
for (let currentArray = stack.at(-1); currentArray !== void 0 && stack.length > 0; currentArray = stack.at(-1)) {
|
|
1333
|
+
const currentNode = currentArray.pop();
|
|
1334
|
+
if (currentNode === void 0) stack.pop();
|
|
1335
|
+
else if ($visit(currentNode) !== false && $isElementNode(currentNode)) stack.push(currentNode.getChildren());
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
function $getTableAndElementByKey(tableNodeKey, editor = $getEditor()) {
|
|
1339
|
+
const tableNode = $getNodeByKey(tableNodeKey);
|
|
1340
|
+
if (!$isTableNode(tableNode)) formatDevErrorMessage(`TableObserver: Expected tableNodeKey ${tableNodeKey} to be a TableNode`);
|
|
1341
|
+
const tableElement = getTableElement(tableNode, editor.getElementByKey(tableNodeKey));
|
|
1342
|
+
if (!(tableElement !== null)) formatDevErrorMessage(`TableObserver: Expected to find TableElement in DOM for key ${tableNodeKey}`);
|
|
1343
|
+
return {
|
|
1344
|
+
tableElement,
|
|
1345
|
+
tableNode
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1349
|
+
* Tracks table selection state that sits across all tables.
|
|
1350
|
+
*/
|
|
1351
|
+
var TableObservers = class {
|
|
1352
|
+
observers;
|
|
1353
|
+
nextFocus;
|
|
1354
|
+
shouldCheckSelectionForTable;
|
|
1355
|
+
constructor() {
|
|
1356
|
+
this.observers = /* @__PURE__ */ new Map();
|
|
1357
|
+
this.nextFocus = null;
|
|
1358
|
+
this.shouldCheckSelectionForTable = null;
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* @internal
|
|
1362
|
+
* When handling mousemove events we track what the focus cell should be, but
|
|
1363
|
+
* the DOM selection may end up somewhere else entirely. We don't have an elegant
|
|
1364
|
+
* way to handle this after the DOM selection has been resolved in a
|
|
1365
|
+
* SELECTION_CHANGE_COMMAND callback.
|
|
1366
|
+
*/
|
|
1367
|
+
setNextFocus(nextFocus) {
|
|
1368
|
+
this.nextFocus = nextFocus;
|
|
1369
|
+
}
|
|
1370
|
+
/** @internal */
|
|
1371
|
+
getAndClearNextFocus() {
|
|
1372
|
+
const { nextFocus } = this;
|
|
1373
|
+
if (nextFocus !== null) this.nextFocus = null;
|
|
1374
|
+
return nextFocus;
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* @internal
|
|
1378
|
+
* Firefox has a strange behavior where pressing the down arrow key from
|
|
1379
|
+
* above the table will move the caret after the table and then lexical
|
|
1380
|
+
* will select the last cell instead of the first.
|
|
1381
|
+
* We do still want to let the browser handle caret movement but we will
|
|
1382
|
+
* use this property to "tag" the update so that we can recheck the
|
|
1383
|
+
* selection after the event is processed.
|
|
1384
|
+
*/
|
|
1385
|
+
setShouldCheckSelectionForTable(tableKey) {
|
|
1386
|
+
this.shouldCheckSelectionForTable = tableKey;
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* @internal
|
|
1390
|
+
*/
|
|
1391
|
+
getAndClearShouldCheckSelectionForTable() {
|
|
1392
|
+
const { shouldCheckSelectionForTable } = this;
|
|
1393
|
+
if (shouldCheckSelectionForTable) {
|
|
1394
|
+
this.shouldCheckSelectionForTable = null;
|
|
1395
|
+
return shouldCheckSelectionForTable;
|
|
1396
|
+
}
|
|
1397
|
+
return null;
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
var TableObserver = class {
|
|
1401
|
+
focusX;
|
|
1402
|
+
focusY;
|
|
1403
|
+
listenersToRemove;
|
|
1404
|
+
table;
|
|
1405
|
+
isHighlightingCells;
|
|
1406
|
+
anchorX;
|
|
1407
|
+
anchorY;
|
|
1408
|
+
tableNodeKey;
|
|
1409
|
+
anchorCell;
|
|
1410
|
+
focusCell;
|
|
1411
|
+
anchorCellNodeKey;
|
|
1412
|
+
focusCellNodeKey;
|
|
1413
|
+
editor;
|
|
1414
|
+
tableSelection;
|
|
1415
|
+
hasHijackedSelectionStyles;
|
|
1416
|
+
isSelecting;
|
|
1417
|
+
pointerType;
|
|
1418
|
+
abortController;
|
|
1419
|
+
listenerOptions;
|
|
1420
|
+
constructor(editor, tableNodeKey) {
|
|
1421
|
+
this.isHighlightingCells = false;
|
|
1422
|
+
this.anchorX = -1;
|
|
1423
|
+
this.anchorY = -1;
|
|
1424
|
+
this.focusX = -1;
|
|
1425
|
+
this.focusY = -1;
|
|
1426
|
+
this.listenersToRemove = /* @__PURE__ */ new Set();
|
|
1427
|
+
this.tableNodeKey = tableNodeKey;
|
|
1428
|
+
this.editor = editor;
|
|
1429
|
+
this.table = {
|
|
1430
|
+
columns: 0,
|
|
1431
|
+
domRows: [],
|
|
1432
|
+
rows: 0
|
|
1433
|
+
};
|
|
1434
|
+
this.tableSelection = null;
|
|
1435
|
+
this.anchorCellNodeKey = null;
|
|
1436
|
+
this.focusCellNodeKey = null;
|
|
1437
|
+
this.anchorCell = null;
|
|
1438
|
+
this.focusCell = null;
|
|
1439
|
+
this.hasHijackedSelectionStyles = false;
|
|
1440
|
+
this.isSelecting = false;
|
|
1441
|
+
this.pointerType = null;
|
|
1442
|
+
this.abortController = new AbortController();
|
|
1443
|
+
this.listenerOptions = { signal: this.abortController.signal };
|
|
1444
|
+
this.trackTable();
|
|
1445
|
+
}
|
|
1446
|
+
getTable() {
|
|
1447
|
+
return this.table;
|
|
1448
|
+
}
|
|
1449
|
+
removeListeners() {
|
|
1450
|
+
this.abortController.abort("removeListeners");
|
|
1451
|
+
Array.from(this.listenersToRemove).forEach((removeListener) => removeListener());
|
|
1452
|
+
this.listenersToRemove.clear();
|
|
1453
|
+
}
|
|
1454
|
+
$lookup() {
|
|
1455
|
+
return $getTableAndElementByKey(this.tableNodeKey, this.editor);
|
|
1456
|
+
}
|
|
1457
|
+
trackTable() {
|
|
1458
|
+
const observer = new MutationObserver((records) => {
|
|
1459
|
+
this.editor.getEditorState().read(() => {
|
|
1460
|
+
let gridNeedsRedraw = false;
|
|
1461
|
+
for (let i = 0; i < records.length; i++) {
|
|
1462
|
+
const nodeName = records[i].target.nodeName;
|
|
1463
|
+
if (nodeName === "TABLE" || nodeName === "TBODY" || nodeName === "THEAD" || nodeName === "TR") {
|
|
1464
|
+
gridNeedsRedraw = true;
|
|
1465
|
+
break;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
if (!gridNeedsRedraw) return;
|
|
1469
|
+
const { tableNode, tableElement } = this.$lookup();
|
|
1470
|
+
this.table = getTable(tableNode, tableElement);
|
|
1471
|
+
}, { editor: this.editor });
|
|
1472
|
+
});
|
|
1473
|
+
this.editor.getEditorState().read(() => {
|
|
1474
|
+
const { tableNode, tableElement } = this.$lookup();
|
|
1475
|
+
this.table = getTable(tableNode, tableElement);
|
|
1476
|
+
observer.observe(tableElement, {
|
|
1477
|
+
attributes: true,
|
|
1478
|
+
childList: true,
|
|
1479
|
+
subtree: true
|
|
1480
|
+
});
|
|
1481
|
+
}, { editor: this.editor });
|
|
1482
|
+
}
|
|
1483
|
+
$clearHighlight(setEmptySelection = true) {
|
|
1484
|
+
const editor = this.editor;
|
|
1485
|
+
this.isHighlightingCells = false;
|
|
1486
|
+
this.anchorX = -1;
|
|
1487
|
+
this.anchorY = -1;
|
|
1488
|
+
this.focusX = -1;
|
|
1489
|
+
this.focusY = -1;
|
|
1490
|
+
this.tableSelection = null;
|
|
1491
|
+
this.anchorCellNodeKey = null;
|
|
1492
|
+
this.focusCellNodeKey = null;
|
|
1493
|
+
this.anchorCell = null;
|
|
1494
|
+
this.focusCell = null;
|
|
1495
|
+
this.hasHijackedSelectionStyles = false;
|
|
1496
|
+
this.$enableHighlightStyle();
|
|
1497
|
+
const { tableNode, tableElement } = this.$lookup();
|
|
1498
|
+
$updateDOMForSelection(editor, getTable(tableNode, tableElement), null);
|
|
1499
|
+
if (setEmptySelection && $getSelection() !== null) {
|
|
1500
|
+
$setSelection(null);
|
|
1501
|
+
editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
$enableHighlightStyle() {
|
|
1505
|
+
const editor = this.editor;
|
|
1506
|
+
const { tableElement } = this.$lookup();
|
|
1507
|
+
removeClassNamesFromElement(tableElement, editor._config.theme.tableSelection);
|
|
1508
|
+
tableElement.classList.remove("disable-selection");
|
|
1509
|
+
this.hasHijackedSelectionStyles = false;
|
|
1510
|
+
}
|
|
1511
|
+
$disableHighlightStyle() {
|
|
1512
|
+
const { tableElement } = this.$lookup();
|
|
1513
|
+
addClassNamesToElement(tableElement, this.editor._config.theme.tableSelection);
|
|
1514
|
+
this.hasHijackedSelectionStyles = true;
|
|
1515
|
+
}
|
|
1516
|
+
$updateTableTableSelection(selection) {
|
|
1517
|
+
if (selection !== null) {
|
|
1518
|
+
if (!(selection.tableKey === this.tableNodeKey)) formatDevErrorMessage(`TableObserver.$updateTableTableSelection: selection.tableKey !== this.tableNodeKey ('${selection.tableKey}' !== '${this.tableNodeKey}')`);
|
|
1519
|
+
const editor = this.editor;
|
|
1520
|
+
this.tableSelection = selection;
|
|
1521
|
+
this.isHighlightingCells = true;
|
|
1522
|
+
this.$disableHighlightStyle();
|
|
1523
|
+
this.updateDOMSelection();
|
|
1524
|
+
$updateDOMForSelection(editor, this.table, this.tableSelection);
|
|
1525
|
+
} else this.$clearHighlight();
|
|
1526
|
+
}
|
|
1527
|
+
/** @internal */
|
|
1528
|
+
updateDOMSelection() {
|
|
1529
|
+
if (this.anchorCell !== null && this.focusCell !== null) {
|
|
1530
|
+
const domSelection = getDOMSelection(this.editor._window);
|
|
1531
|
+
if (domSelection && domSelection.rangeCount > 0) domSelection.removeAllRanges();
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
$setFocusCellForSelection(cell, ignoreStart = false) {
|
|
1535
|
+
const editor = this.editor;
|
|
1536
|
+
const { tableNode } = this.$lookup();
|
|
1537
|
+
const cellX = cell.x;
|
|
1538
|
+
const cellY = cell.y;
|
|
1539
|
+
this.focusCell = cell;
|
|
1540
|
+
if (!this.isHighlightingCells) {
|
|
1541
|
+
if (ignoreStart || this.anchorX !== cellX || this.anchorY !== cellY || this.tableSelection != null && this.anchorCellNodeKey != null) {
|
|
1542
|
+
this.isHighlightingCells = true;
|
|
1543
|
+
this.$disableHighlightStyle();
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
if (this.focusX !== -1 && this.focusY !== -1 && cellX === this.focusX && cellY === this.focusY) return false;
|
|
1547
|
+
this.focusX = cellX;
|
|
1548
|
+
this.focusY = cellY;
|
|
1549
|
+
if (this.isHighlightingCells) {
|
|
1550
|
+
const focusTableCellNode = $getNearestTableCellInTableFromDOMNode(tableNode, cell.elem);
|
|
1551
|
+
if (this.tableSelection != null && this.anchorCellNodeKey != null) {
|
|
1552
|
+
let targetCellNode = focusTableCellNode;
|
|
1553
|
+
if (targetCellNode === null && ignoreStart) targetCellNode = tableNode.getCellNodeFromCords(cellX, cellY, this.table);
|
|
1554
|
+
if (targetCellNode !== null) {
|
|
1555
|
+
const anchorTableCell = this.$getAnchorTableCellOrThrow();
|
|
1556
|
+
this.focusCellNodeKey = targetCellNode.getKey();
|
|
1557
|
+
this.tableSelection = $createTableSelectionFrom(tableNode, anchorTableCell, targetCellNode);
|
|
1558
|
+
$setSelection(this.tableSelection);
|
|
1559
|
+
editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0);
|
|
1560
|
+
$updateDOMForSelection(editor, this.table, this.tableSelection);
|
|
1561
|
+
return true;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
return false;
|
|
1566
|
+
}
|
|
1567
|
+
$getAnchorTableCell() {
|
|
1568
|
+
return this.anchorCellNodeKey ? $getNodeByKey(this.anchorCellNodeKey) : null;
|
|
1569
|
+
}
|
|
1570
|
+
$getAnchorTableCellOrThrow() {
|
|
1571
|
+
const anchorTableCell = this.$getAnchorTableCell();
|
|
1572
|
+
if (!(anchorTableCell !== null)) formatDevErrorMessage(`TableObserver anchorTableCell is null`);
|
|
1573
|
+
return anchorTableCell;
|
|
1574
|
+
}
|
|
1575
|
+
$getFocusTableCell() {
|
|
1576
|
+
return this.focusCellNodeKey ? $getNodeByKey(this.focusCellNodeKey) : null;
|
|
1577
|
+
}
|
|
1578
|
+
$getFocusTableCellOrThrow() {
|
|
1579
|
+
const focusTableCell = this.$getFocusTableCell();
|
|
1580
|
+
if (!(focusTableCell !== null)) formatDevErrorMessage(`TableObserver focusTableCell is null`);
|
|
1581
|
+
return focusTableCell;
|
|
1582
|
+
}
|
|
1583
|
+
$setAnchorCellForSelection(cell) {
|
|
1584
|
+
this.isHighlightingCells = false;
|
|
1585
|
+
this.anchorCell = cell;
|
|
1586
|
+
this.anchorX = cell.x;
|
|
1587
|
+
this.anchorY = cell.y;
|
|
1588
|
+
this.focusX = -1;
|
|
1589
|
+
this.focusY = -1;
|
|
1590
|
+
this.focusCell = null;
|
|
1591
|
+
this.focusCellNodeKey = null;
|
|
1592
|
+
const { tableNode } = this.$lookup();
|
|
1593
|
+
const anchorTableCellNode = $getNearestTableCellInTableFromDOMNode(tableNode, cell.elem);
|
|
1594
|
+
if (anchorTableCellNode !== null) {
|
|
1595
|
+
const anchorNodeKey = anchorTableCellNode.getKey();
|
|
1596
|
+
if (this.tableSelection != null) {
|
|
1597
|
+
this.tableSelection = this.tableSelection.clone();
|
|
1598
|
+
this.tableSelection.set(tableNode.getKey(), anchorNodeKey, anchorNodeKey);
|
|
1599
|
+
} else this.tableSelection = $createTableSelectionFrom(tableNode, anchorTableCellNode, anchorTableCellNode);
|
|
1600
|
+
this.anchorCellNodeKey = anchorNodeKey;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
$formatCells(type) {
|
|
1604
|
+
const selection = $getSelection();
|
|
1605
|
+
if (!$isTableSelection(selection)) formatDevErrorMessage(`Expected Table selection`);
|
|
1606
|
+
const formatSelection = $createRangeSelection();
|
|
1607
|
+
const anchor = formatSelection.anchor;
|
|
1608
|
+
const focus = formatSelection.focus;
|
|
1609
|
+
const cellNodes = selection.getNodes().filter($isTableCellNode);
|
|
1610
|
+
if (!(cellNodes.length > 0)) formatDevErrorMessage(`No table cells present`);
|
|
1611
|
+
const paragraph = cellNodes[0].getFirstChild();
|
|
1612
|
+
const alignFormatWith = $isParagraphNode(paragraph) ? paragraph.getFormatFlags(type, null) : null;
|
|
1613
|
+
cellNodes.forEach((cellNode) => {
|
|
1614
|
+
anchor.set(cellNode.getKey(), 0, "element");
|
|
1615
|
+
focus.set(cellNode.getKey(), cellNode.getChildrenSize(), "element");
|
|
1616
|
+
formatSelection.formatText(type, alignFormatWith);
|
|
1617
|
+
});
|
|
1618
|
+
$setSelection(selection);
|
|
1619
|
+
this.editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0);
|
|
1620
|
+
}
|
|
1621
|
+
$clearText() {
|
|
1622
|
+
const { editor } = this;
|
|
1623
|
+
const tableNode = $getNodeByKey(this.tableNodeKey);
|
|
1624
|
+
if (!$isTableNode(tableNode)) throw new Error("Expected TableNode.");
|
|
1625
|
+
const selection = $getSelection();
|
|
1626
|
+
if (!$isTableSelection(selection)) formatDevErrorMessage(`Expected TableSelection`);
|
|
1627
|
+
const selectedNodes = selection.getNodes().filter($isTableCellNode);
|
|
1628
|
+
const firstRow = tableNode.getFirstChild();
|
|
1629
|
+
const lastRow = tableNode.getLastChild();
|
|
1630
|
+
if (selectedNodes.length > 0 && firstRow !== null && lastRow !== null && $isTableRowNode(firstRow) && $isTableRowNode(lastRow) && selectedNodes[0] === firstRow.getFirstChild() && selectedNodes[selectedNodes.length - 1] === lastRow.getLastChild()) {
|
|
1631
|
+
tableNode.selectPrevious();
|
|
1632
|
+
const parent = tableNode.getParent();
|
|
1633
|
+
tableNode.remove();
|
|
1634
|
+
if ($isRootNode(parent) && parent.isEmpty()) editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND, void 0);
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
selectedNodes.forEach((cellNode) => {
|
|
1638
|
+
if ($isElementNode(cellNode)) {
|
|
1639
|
+
const paragraphNode = $createParagraphNode();
|
|
1640
|
+
const textNode = $createTextNode();
|
|
1641
|
+
paragraphNode.append(textNode);
|
|
1642
|
+
cellNode.append(paragraphNode);
|
|
1643
|
+
cellNode.getChildren().forEach((child) => {
|
|
1644
|
+
if (child !== paragraphNode) child.remove();
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
});
|
|
1648
|
+
$updateDOMForSelection(editor, this.table, null);
|
|
1649
|
+
$setSelection(null);
|
|
1650
|
+
editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0);
|
|
1651
|
+
}
|
|
1652
|
+
};
|
|
1653
|
+
const LEXICAL_ELEMENT_KEY = "__lexicalTableSelection";
|
|
1654
|
+
const isPointerDownOnEvent = (event) => {
|
|
1655
|
+
return (event.buttons & 1) === 1;
|
|
1656
|
+
};
|
|
1657
|
+
function isHTMLTableElement(el) {
|
|
1658
|
+
return isHTMLElement(el) && el.nodeName === "TABLE";
|
|
1659
|
+
}
|
|
1660
|
+
function getTableElement(tableNode, dom) {
|
|
1661
|
+
if (!dom) return dom;
|
|
1662
|
+
const element = isHTMLTableElement(dom) ? dom : dom.querySelector("table");
|
|
1663
|
+
if (!isHTMLTableElement(element)) formatDevErrorMessage(`getTableElement: Expecting table in DOM node for ${tableNode.constructor.name} of type ${tableNode.getType()} with key ${tableNode.getKey()}, not ${dom.nodeName}`);
|
|
1664
|
+
return element;
|
|
1665
|
+
}
|
|
1666
|
+
function getEditorWindow(editor) {
|
|
1667
|
+
return editor._window;
|
|
1668
|
+
}
|
|
1669
|
+
function $findParentTableCellNodeInTable(tableNode, node) {
|
|
1670
|
+
for (let currentNode = node, lastTableCellNode = null; currentNode !== null; currentNode = currentNode.getParent()) if (tableNode.is(currentNode)) return lastTableCellNode;
|
|
1671
|
+
else if ($isTableCellNode(currentNode)) lastTableCellNode = currentNode;
|
|
1672
|
+
return null;
|
|
1673
|
+
}
|
|
1674
|
+
const ARROW_KEY_COMMANDS_WITH_DIRECTION = [
|
|
1675
|
+
[KEY_ARROW_DOWN_COMMAND, "down"],
|
|
1676
|
+
[KEY_ARROW_UP_COMMAND, "up"],
|
|
1677
|
+
[KEY_ARROW_LEFT_COMMAND, "backward"],
|
|
1678
|
+
[KEY_ARROW_RIGHT_COMMAND, "forward"]
|
|
1679
|
+
];
|
|
1680
|
+
const DELETE_TEXT_COMMANDS = [
|
|
1681
|
+
DELETE_WORD_COMMAND,
|
|
1682
|
+
DELETE_LINE_COMMAND,
|
|
1683
|
+
DELETE_CHARACTER_COMMAND
|
|
1684
|
+
];
|
|
1685
|
+
const DELETE_KEY_COMMANDS = [KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND];
|
|
1686
|
+
function registerTableWindowHandlers(editor, tableObservers) {
|
|
1687
|
+
const rootElement = editor.getRootElement();
|
|
1688
|
+
const editorWindow = editor._window;
|
|
1689
|
+
if (!rootElement || !editorWindow) return () => {};
|
|
1690
|
+
const pointerDownCallback = (event) => {
|
|
1691
|
+
const target = event.target;
|
|
1692
|
+
if (event.button !== 0 || !isDOMNode(target) || !rootElement.contains(target)) return;
|
|
1693
|
+
const selectionInfo = getTableObserverFromCellNode(target);
|
|
1694
|
+
editor.update(() => {
|
|
1695
|
+
if ($isTableSelection($getSelection())) {
|
|
1696
|
+
for (const [observer] of tableObservers.observers.values()) observer.$clearHighlight(false);
|
|
1697
|
+
$setSelection(null);
|
|
1698
|
+
editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0);
|
|
1699
|
+
}
|
|
1700
|
+
if (!selectionInfo) return;
|
|
1701
|
+
const { tableObserver, tableElement, cellElement } = selectionInfo;
|
|
1702
|
+
$handleTableClick(editor, event, cellElement, tableElement, tableObserver, tableObservers);
|
|
1703
|
+
});
|
|
1704
|
+
};
|
|
1705
|
+
editorWindow.addEventListener("pointerdown", pointerDownCallback);
|
|
1706
|
+
return () => {
|
|
1707
|
+
editorWindow.removeEventListener("pointerdown", pointerDownCallback);
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
function $handleTableClick(editor, event, selectedDOMCell, tableElement, tableObserver, tableObservers) {
|
|
1711
|
+
const editorWindow = editor._window;
|
|
1712
|
+
if (!editorWindow) return;
|
|
1713
|
+
const createPointerHandlers = (startingCell) => {
|
|
1714
|
+
if (tableObserver.isSelecting) return;
|
|
1715
|
+
tableObserver.isSelecting = true;
|
|
1716
|
+
if (startingCell !== null && tableObserver.anchorCell === null) editor.update(() => {
|
|
1717
|
+
tableObserver.$setAnchorCellForSelection(startingCell);
|
|
1718
|
+
});
|
|
1719
|
+
const onPointerUp = () => {
|
|
1720
|
+
tableObserver.isSelecting = false;
|
|
1721
|
+
editorWindow.removeEventListener("pointerup", onPointerUp);
|
|
1722
|
+
editorWindow.removeEventListener("pointermove", onPointerMove);
|
|
1723
|
+
};
|
|
1724
|
+
const onPointerMove = (moveEvent) => {
|
|
1725
|
+
if (!isPointerDownOnEvent(moveEvent) && tableObserver.isSelecting) {
|
|
1726
|
+
tableObserver.isSelecting = false;
|
|
1727
|
+
editorWindow.removeEventListener("pointerup", onPointerUp);
|
|
1728
|
+
editorWindow.removeEventListener("pointermove", onPointerMove);
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
if (!isDOMNode(moveEvent.target)) return;
|
|
1732
|
+
let focusCell = null;
|
|
1733
|
+
const override = !(IS_FIREFOX || tableElement.contains(moveEvent.target));
|
|
1734
|
+
if (override) focusCell = getDOMCellInTableFromTarget(tableElement, moveEvent.target);
|
|
1735
|
+
else for (const el of document.elementsFromPoint(moveEvent.clientX, moveEvent.clientY)) {
|
|
1736
|
+
focusCell = getDOMCellInTableFromTarget(tableElement, el);
|
|
1737
|
+
if (focusCell) break;
|
|
1738
|
+
}
|
|
1739
|
+
if (focusCell) {
|
|
1740
|
+
const anchorCell = focusCell;
|
|
1741
|
+
if (tableObserver.anchorCell === null) editor.update(() => {
|
|
1742
|
+
tableObserver.$setAnchorCellForSelection(anchorCell);
|
|
1743
|
+
});
|
|
1744
|
+
if (tableObserver.focusCell === null || focusCell.elem !== tableObserver.focusCell.elem) {
|
|
1745
|
+
tableObservers.setNextFocus({
|
|
1746
|
+
focusCell,
|
|
1747
|
+
override,
|
|
1748
|
+
tableKey: tableObserver.tableNodeKey
|
|
1749
|
+
});
|
|
1750
|
+
editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
};
|
|
1754
|
+
editorWindow.addEventListener("pointerup", onPointerUp, tableObserver.listenerOptions);
|
|
1755
|
+
editorWindow.addEventListener("pointermove", onPointerMove, tableObserver.listenerOptions);
|
|
1756
|
+
};
|
|
1757
|
+
tableObserver.pointerType = event.pointerType;
|
|
1758
|
+
const tableNode = $getNodeByKeyOrThrow(tableObserver.tableNodeKey);
|
|
1759
|
+
const prevSelection = $getPreviousSelection();
|
|
1760
|
+
if (IS_FIREFOX && event.shiftKey && $isSelectionInTable(prevSelection, tableNode) && ($isRangeSelection(prevSelection) || $isTableSelection(prevSelection))) {
|
|
1761
|
+
const prevAnchorNode = prevSelection.anchor.getNode();
|
|
1762
|
+
const prevAnchorCell = $findParentTableCellNodeInTable(tableNode, prevSelection.anchor.getNode());
|
|
1763
|
+
if (prevAnchorCell) {
|
|
1764
|
+
tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, prevAnchorCell));
|
|
1765
|
+
tableObserver.$setFocusCellForSelection(selectedDOMCell);
|
|
1766
|
+
stopEvent(event);
|
|
1767
|
+
} else (tableNode.isBefore(prevAnchorNode) ? tableNode.selectStart() : tableNode.selectEnd()).anchor.set(prevSelection.anchor.key, prevSelection.anchor.offset, prevSelection.anchor.type);
|
|
1768
|
+
} else if (event.pointerType !== "touch") tableObserver.$setAnchorCellForSelection(selectedDOMCell);
|
|
1769
|
+
createPointerHandlers(selectedDOMCell);
|
|
1770
|
+
}
|
|
1771
|
+
function applyTableHandlers(tableNode, element, editor, hasTabHandler, tableObservers) {
|
|
1772
|
+
const rootElement = editor.getRootElement();
|
|
1773
|
+
const editorWindow = getEditorWindow(editor);
|
|
1774
|
+
if (!(rootElement !== null && editorWindow !== null)) formatDevErrorMessage(`applyTableHandlers: editor has no root element set`);
|
|
1775
|
+
const tableObserver = new TableObserver(editor, tableNode.getKey());
|
|
1776
|
+
const tableElement = getTableElement(tableNode, element);
|
|
1777
|
+
attachTableObserverToTableElement(tableElement, tableObserver);
|
|
1778
|
+
tableObserver.listenersToRemove.add(() => detachTableObserverFromTableElement(tableElement, tableObserver));
|
|
1779
|
+
const onTripleClick = (event) => {
|
|
1780
|
+
if (event.detail >= 3 && isDOMNode(event.target)) {
|
|
1781
|
+
if (getDOMCellFromTarget(event.target) !== null) event.preventDefault();
|
|
1782
|
+
}
|
|
1783
|
+
};
|
|
1784
|
+
tableElement.addEventListener("mousedown", onTripleClick, tableObserver.listenerOptions);
|
|
1785
|
+
tableObserver.listenersToRemove.add(() => {
|
|
1786
|
+
tableElement.removeEventListener("mousedown", onTripleClick);
|
|
1787
|
+
});
|
|
1788
|
+
for (const [command, direction] of ARROW_KEY_COMMANDS_WITH_DIRECTION) tableObserver.listenersToRemove.add(editor.registerCommand(command, (event) => $handleArrowKey(editor, event, direction, tableNode, tableObserver, tableObservers), COMMAND_PRIORITY_HIGH));
|
|
1789
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(KEY_ESCAPE_COMMAND, (event) => {
|
|
1790
|
+
const selection = $getSelection();
|
|
1791
|
+
if ($isTableSelection(selection)) {
|
|
1792
|
+
const focusCellNode = $findParentTableCellNodeInTable(tableNode, selection.focus.getNode());
|
|
1793
|
+
if (focusCellNode !== null) {
|
|
1794
|
+
stopEvent(event);
|
|
1795
|
+
focusCellNode.selectEnd();
|
|
1796
|
+
return true;
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
return false;
|
|
1800
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
1801
|
+
const deleteTextHandler = (command) => () => {
|
|
1802
|
+
const selection = $getSelection();
|
|
1803
|
+
if (!$isSelectionInTable(selection, tableNode)) return false;
|
|
1804
|
+
if ($isTableSelection(selection)) {
|
|
1805
|
+
tableObserver.$clearText();
|
|
1806
|
+
return true;
|
|
1807
|
+
} else if ($isRangeSelection(selection)) {
|
|
1808
|
+
if (!$isTableCellNode($findParentTableCellNodeInTable(tableNode, selection.anchor.getNode()))) return false;
|
|
1809
|
+
const anchorNode = selection.anchor.getNode();
|
|
1810
|
+
const focusNode = selection.focus.getNode();
|
|
1811
|
+
const isAnchorInside = tableNode.isParentOf(anchorNode);
|
|
1812
|
+
const isFocusInside = tableNode.isParentOf(focusNode);
|
|
1813
|
+
if (isAnchorInside && !isFocusInside || isFocusInside && !isAnchorInside) {
|
|
1814
|
+
tableObserver.$clearText();
|
|
1815
|
+
return true;
|
|
1816
|
+
}
|
|
1817
|
+
const nearestElementNode = $findMatchingParent(selection.anchor.getNode(), (n) => $isElementNode(n));
|
|
1818
|
+
const topLevelCellElementNode = nearestElementNode && $findMatchingParent(nearestElementNode, (n) => $isElementNode(n) && $isTableCellNode(n.getParent()));
|
|
1819
|
+
if (!$isElementNode(topLevelCellElementNode) || !$isElementNode(nearestElementNode)) return false;
|
|
1820
|
+
if (command === DELETE_LINE_COMMAND && topLevelCellElementNode.getPreviousSibling() === null) return true;
|
|
1821
|
+
}
|
|
1822
|
+
return false;
|
|
1823
|
+
};
|
|
1824
|
+
for (const command of DELETE_TEXT_COMMANDS) tableObserver.listenersToRemove.add(editor.registerCommand(command, deleteTextHandler(command), COMMAND_PRIORITY_HIGH));
|
|
1825
|
+
const $deleteCellHandler = (event) => {
|
|
1826
|
+
const selection = $getSelection();
|
|
1827
|
+
if (!($isTableSelection(selection) || $isRangeSelection(selection))) return false;
|
|
1828
|
+
const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode());
|
|
1829
|
+
if (isAnchorInside !== tableNode.isParentOf(selection.focus.getNode())) {
|
|
1830
|
+
const tablePoint = isAnchorInside ? "anchor" : "focus";
|
|
1831
|
+
const outerPoint = isAnchorInside ? "focus" : "anchor";
|
|
1832
|
+
const { key, offset, type } = selection[outerPoint];
|
|
1833
|
+
tableNode[selection[tablePoint].isBefore(selection[outerPoint]) ? "selectPrevious" : "selectNext"]()[outerPoint].set(key, offset, type);
|
|
1834
|
+
return false;
|
|
1835
|
+
}
|
|
1836
|
+
if (!$isSelectionInTable(selection, tableNode)) return false;
|
|
1837
|
+
if ($isTableSelection(selection)) {
|
|
1838
|
+
if (event) {
|
|
1839
|
+
event.preventDefault();
|
|
1840
|
+
event.stopPropagation();
|
|
1841
|
+
}
|
|
1842
|
+
tableObserver.$clearText();
|
|
1843
|
+
return true;
|
|
1844
|
+
}
|
|
1845
|
+
return false;
|
|
1846
|
+
};
|
|
1847
|
+
for (const command of DELETE_KEY_COMMANDS) tableObserver.listenersToRemove.add(editor.registerCommand(command, $deleteCellHandler, COMMAND_PRIORITY_HIGH));
|
|
1848
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(CUT_COMMAND, (event) => {
|
|
1849
|
+
const selection = $getSelection();
|
|
1850
|
+
if (selection) {
|
|
1851
|
+
if (!($isTableSelection(selection) || $isRangeSelection(selection))) return false;
|
|
1852
|
+
copyToClipboard(editor, objectKlassEquals(event, ClipboardEvent) ? event : null, $getClipboardDataFromSelection(selection));
|
|
1853
|
+
const intercepted = $deleteCellHandler(event);
|
|
1854
|
+
if ($isRangeSelection(selection)) {
|
|
1855
|
+
selection.removeText();
|
|
1856
|
+
return true;
|
|
1857
|
+
}
|
|
1858
|
+
return intercepted;
|
|
1859
|
+
}
|
|
1860
|
+
return false;
|
|
1861
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
1862
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(FORMAT_TEXT_COMMAND, (payload) => {
|
|
1863
|
+
const selection = $getSelection();
|
|
1864
|
+
if (!$isSelectionInTable(selection, tableNode)) return false;
|
|
1865
|
+
if ($isTableSelection(selection)) {
|
|
1866
|
+
tableObserver.$formatCells(payload);
|
|
1867
|
+
return true;
|
|
1868
|
+
} else if ($isRangeSelection(selection)) {
|
|
1869
|
+
if (!$isTableCellNode($findMatchingParent(selection.anchor.getNode(), (n) => $isTableCellNode(n)))) return false;
|
|
1870
|
+
}
|
|
1871
|
+
return false;
|
|
1872
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
1873
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(FORMAT_ELEMENT_COMMAND, (formatType) => {
|
|
1874
|
+
const selection = $getSelection();
|
|
1875
|
+
if (!$isTableSelection(selection) || !$isSelectionInTable(selection, tableNode)) return false;
|
|
1876
|
+
const anchorNode = selection.anchor.getNode();
|
|
1877
|
+
const focusNode = selection.focus.getNode();
|
|
1878
|
+
if (!$isTableCellNode(anchorNode) || !$isTableCellNode(focusNode)) return false;
|
|
1879
|
+
if ($isFullTableSelection(selection, tableNode)) {
|
|
1880
|
+
tableNode.setFormat(formatType);
|
|
1881
|
+
return true;
|
|
1882
|
+
}
|
|
1883
|
+
const [tableMap, anchorCell, focusCell] = $computeTableMap(tableNode, anchorNode, focusNode);
|
|
1884
|
+
const maxRow = Math.max(anchorCell.startRow + anchorCell.cell.__rowSpan - 1, focusCell.startRow + focusCell.cell.__rowSpan - 1);
|
|
1885
|
+
const maxColumn = Math.max(anchorCell.startColumn + anchorCell.cell.__colSpan - 1, focusCell.startColumn + focusCell.cell.__colSpan - 1);
|
|
1886
|
+
const minRow = Math.min(anchorCell.startRow, focusCell.startRow);
|
|
1887
|
+
const minColumn = Math.min(anchorCell.startColumn, focusCell.startColumn);
|
|
1888
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1889
|
+
for (let i = minRow; i <= maxRow; i++) for (let j = minColumn; j <= maxColumn; j++) {
|
|
1890
|
+
const cell = tableMap[i][j].cell;
|
|
1891
|
+
if (visited.has(cell)) continue;
|
|
1892
|
+
visited.add(cell);
|
|
1893
|
+
cell.setFormat(formatType);
|
|
1894
|
+
const cellChildren = cell.getChildren();
|
|
1895
|
+
for (let k = 0; k < cellChildren.length; k++) {
|
|
1896
|
+
const child = cellChildren[k];
|
|
1897
|
+
if ($isElementNode(child) && !child.isInline()) child.setFormat(formatType);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
return true;
|
|
1901
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
1902
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(CONTROLLED_TEXT_INSERTION_COMMAND, (payload) => {
|
|
1903
|
+
const selection = $getSelection();
|
|
1904
|
+
if (!$isSelectionInTable(selection, tableNode)) return false;
|
|
1905
|
+
if ($isTableSelection(selection)) {
|
|
1906
|
+
tableObserver.$clearHighlight();
|
|
1907
|
+
return false;
|
|
1908
|
+
} else if ($isRangeSelection(selection)) {
|
|
1909
|
+
if (!$isTableCellNode($findMatchingParent(selection.anchor.getNode(), (n) => $isTableCellNode(n)))) return false;
|
|
1910
|
+
if (typeof payload === "string") {
|
|
1911
|
+
const edgePosition = $getTableEdgeCursorPosition(editor, selection, tableNode);
|
|
1912
|
+
if (edgePosition) {
|
|
1913
|
+
$insertParagraphAtTableEdge(edgePosition, tableNode, [$createTextNode(payload)]);
|
|
1914
|
+
return true;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
return false;
|
|
1919
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
1920
|
+
if (hasTabHandler) tableObserver.listenersToRemove.add(editor.registerCommand(KEY_TAB_COMMAND, (event) => {
|
|
1921
|
+
const selection = $getSelection();
|
|
1922
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed() || !$isSelectionInTable(selection, tableNode)) return false;
|
|
1923
|
+
const tableCellNode = $findCellNode(selection.anchor.getNode());
|
|
1924
|
+
if (tableCellNode === null || !tableNode.is($findTableNode(tableCellNode))) return false;
|
|
1925
|
+
stopEvent(event);
|
|
1926
|
+
$selectAdjacentCell(tableCellNode, event.shiftKey ? "previous" : "next");
|
|
1927
|
+
return true;
|
|
1928
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
1929
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(FOCUS_COMMAND, (payload) => {
|
|
1930
|
+
return tableNode.isSelected();
|
|
1931
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
1932
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(INSERT_PARAGRAPH_COMMAND, () => {
|
|
1933
|
+
const selection = $getSelection();
|
|
1934
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed() || !$isSelectionInTable(selection, tableNode)) return false;
|
|
1935
|
+
const edgePosition = $getTableEdgeCursorPosition(editor, selection, tableNode);
|
|
1936
|
+
if (edgePosition) {
|
|
1937
|
+
$insertParagraphAtTableEdge(edgePosition, tableNode);
|
|
1938
|
+
return true;
|
|
1939
|
+
}
|
|
1940
|
+
return false;
|
|
1941
|
+
}, COMMAND_PRIORITY_HIGH));
|
|
1942
|
+
return tableObserver;
|
|
1943
|
+
}
|
|
1944
|
+
/** @internal */
|
|
1945
|
+
function $handleTableSelectionChangeCommand(tableObservers, editor) {
|
|
1946
|
+
const selection = $getSelection();
|
|
1947
|
+
const prevSelection = $getPreviousSelection();
|
|
1948
|
+
const nextFocus = tableObservers.getAndClearNextFocus();
|
|
1949
|
+
if (nextFocus !== null) {
|
|
1950
|
+
const { tableKey, focusCell } = nextFocus;
|
|
1951
|
+
const observerAndTable = tableObservers.observers.get(tableKey);
|
|
1952
|
+
if (!!!observerAndTable) formatDevErrorMessage(`tableObserver not found for tableKey: ${tableKey}`);
|
|
1953
|
+
const [tableObserver] = observerAndTable;
|
|
1954
|
+
if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey) if (focusCell.x === tableObserver.focusX && focusCell.y === tableObserver.focusY) return false;
|
|
1955
|
+
else {
|
|
1956
|
+
tableObserver.$setFocusCellForSelection(focusCell);
|
|
1957
|
+
return true;
|
|
1958
|
+
}
|
|
1959
|
+
else if (tableObserver.anchorCell !== null && tableObserver.anchorCellNodeKey !== null && focusCell.elem !== tableObserver.anchorCell.elem && tableObserver.tableSelection !== null) {
|
|
1960
|
+
tableObserver.$setFocusCellForSelection(focusCell, true);
|
|
1961
|
+
return true;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
const shouldCheckSelectionForTable = tableObservers.getAndClearShouldCheckSelectionForTable();
|
|
1965
|
+
if (!!shouldCheckSelectionForTable && $isRangeSelection(prevSelection) && $isRangeSelection(selection) && selection.isCollapsed()) {
|
|
1966
|
+
const tableNode = $getNodeByKeyOrThrow(shouldCheckSelectionForTable);
|
|
1967
|
+
const anchor = selection.anchor.getNode();
|
|
1968
|
+
const firstRow = tableNode.getFirstChild();
|
|
1969
|
+
const anchorCell = $findCellNode(anchor);
|
|
1970
|
+
if (anchorCell !== null && $isTableRowNode(firstRow)) {
|
|
1971
|
+
const firstCell = firstRow.getFirstChild();
|
|
1972
|
+
if ($isTableCellNode(firstCell) && tableNode.is($findMatchingParent(anchorCell, (node) => node.is(tableNode) || node.is(firstCell)))) {
|
|
1973
|
+
firstCell.selectStart();
|
|
1974
|
+
return true;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
if ($isTableSelection(selection)) $fixTableSelectionForSelectedTable(editor, selection);
|
|
1979
|
+
if ($isRangeSelection(selection)) $fixRangeSelectionForSelectedTable(selection, tableObservers);
|
|
1980
|
+
const tableNodesAndObservers = Array.from(tableObservers.observers.entries()).map(([tableKey, [tableObserver]]) => ({
|
|
1981
|
+
tableNode: $getNodeByKeyOrThrow(tableKey),
|
|
1982
|
+
tableObserver
|
|
1983
|
+
}));
|
|
1984
|
+
for (const { tableNode, tableObserver } of tableNodesAndObservers) $syncTableSelectionState(editor, tableNode, tableObserver);
|
|
1985
|
+
return false;
|
|
1986
|
+
}
|
|
1987
|
+
/**
|
|
1988
|
+
* Handles cases where range selections cross into, out of, or within tables.
|
|
1989
|
+
*/
|
|
1990
|
+
function $fixRangeSelectionForSelectedTable(selection, tableObservers) {
|
|
1991
|
+
const prevSelection = $getPreviousSelection();
|
|
1992
|
+
const { anchor, focus } = selection;
|
|
1993
|
+
const anchorNode = anchor.getNode();
|
|
1994
|
+
const focusNode = focus.getNode();
|
|
1995
|
+
const anchorCellNode = $findCellNode(anchorNode);
|
|
1996
|
+
const focusCellNode = $findCellNode(focusNode);
|
|
1997
|
+
const anchorCellTable = anchorCellNode ? $findTableNode(anchorCellNode) : null;
|
|
1998
|
+
const focusCellTable = focusCellNode ? $findTableNode(focusCellNode) : null;
|
|
1999
|
+
const isBackward = selection.isBackward();
|
|
2000
|
+
const isSameTable = anchorCellNode && focusCellNode && anchorCellTable && focusCellTable && anchorCellTable.is(focusCellTable);
|
|
2001
|
+
const shouldMoveFocus = focusCellTable && (!anchorCellTable || anchorCellTable.isParentOf(focusCellTable));
|
|
2002
|
+
const shouldMoveAnchor = anchorCellTable && (!focusCellTable || focusCellTable.isParentOf(anchorCellTable));
|
|
2003
|
+
if (shouldMoveFocus) {
|
|
2004
|
+
const newSelection = selection.clone();
|
|
2005
|
+
const [tableMap] = $computeTableMap(focusCellTable, focusCellNode, focusCellNode);
|
|
2006
|
+
const firstCell = tableMap[0][0].cell;
|
|
2007
|
+
const lastCell = tableMap[tableMap.length - 1].at(-1).cell;
|
|
2008
|
+
newSelection.focus.set(isBackward ? firstCell.getKey() : lastCell.getKey(), isBackward ? 0 : lastCell.getChildrenSize(), "element");
|
|
2009
|
+
$setSelection(newSelection);
|
|
2010
|
+
} else if (shouldMoveAnchor) {
|
|
2011
|
+
const newSelection = selection.clone();
|
|
2012
|
+
const [tableMap] = $computeTableMap(anchorCellTable, anchorCellNode, anchorCellNode);
|
|
2013
|
+
const firstCell = tableMap[0][0].cell;
|
|
2014
|
+
const lastCell = tableMap[tableMap.length - 1].at(-1).cell;
|
|
2015
|
+
newSelection.anchor.set(isBackward ? lastCell.getKey() : firstCell.getKey(), isBackward ? lastCell.getChildrenSize() : 0, "element");
|
|
2016
|
+
$setSelection(newSelection);
|
|
2017
|
+
} else if (isSameTable) {
|
|
2018
|
+
const observerInfo = tableObservers.observers.get(anchorCellTable.getKey());
|
|
2019
|
+
if (!!!observerInfo) formatDevErrorMessage(`tableObserver not found for tableKey: ${anchorCellTable.getKey()}`);
|
|
2020
|
+
const [tableObserver] = observerInfo;
|
|
2021
|
+
if (!anchorCellNode.is(focusCellNode)) {
|
|
2022
|
+
tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, anchorCellNode));
|
|
2023
|
+
tableObserver.$setFocusCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, focusCellNode), true);
|
|
2024
|
+
}
|
|
2025
|
+
if (tableObserver.pointerType === "touch" && tableObserver.isSelecting && selection.isCollapsed() && $isRangeSelection(prevSelection) && prevSelection.isCollapsed()) {
|
|
2026
|
+
const prevAnchorCellNode = $findCellNode(prevSelection.anchor.getNode());
|
|
2027
|
+
if (prevAnchorCellNode && !prevAnchorCellNode.is(focusCellNode)) {
|
|
2028
|
+
tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, prevAnchorCellNode));
|
|
2029
|
+
tableObserver.$setFocusCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, focusCellNode), true);
|
|
2030
|
+
tableObserver.pointerType = null;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Ensures that a TableSelection is automatically changed to a RangeSelection when the selection goes outside of the table.
|
|
2037
|
+
*/
|
|
2038
|
+
function $fixTableSelectionForSelectedTable(editor, selection) {
|
|
2039
|
+
const editorWindow = getEditorWindow(editor);
|
|
2040
|
+
const prevSelection = $getPreviousSelection();
|
|
2041
|
+
if (!selection.is(prevSelection)) return;
|
|
2042
|
+
const tableNode = $getNodeByKeyOrThrow(selection.tableKey);
|
|
2043
|
+
const domSelection = getDOMSelection(editorWindow);
|
|
2044
|
+
if (domSelection && domSelection.anchorNode && domSelection.focusNode) {
|
|
2045
|
+
const focusNode = $getNearestNodeFromDOMNode(domSelection.focusNode);
|
|
2046
|
+
const isFocusOutside = focusNode && !tableNode.isParentOf(focusNode);
|
|
2047
|
+
const anchorNode = $getNearestNodeFromDOMNode(domSelection.anchorNode);
|
|
2048
|
+
const isAnchorInside = anchorNode && tableNode.isParentOf(anchorNode);
|
|
2049
|
+
if (isFocusOutside && isAnchorInside && domSelection.rangeCount > 0) {
|
|
2050
|
+
const newSelection = $createRangeSelectionFromDom(domSelection, editor);
|
|
2051
|
+
if (newSelection) {
|
|
2052
|
+
newSelection.anchor.set(tableNode.getKey(), selection.isBackward() ? tableNode.getChildrenSize() : 0, "element");
|
|
2053
|
+
domSelection.removeAllRanges();
|
|
2054
|
+
$setSelection(newSelection);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
function $syncTableSelectionState(editor, tableNode, tableObserver) {
|
|
2060
|
+
const selection = $getSelection();
|
|
2061
|
+
const prevSelection = $getPreviousSelection();
|
|
2062
|
+
if (selection && !selection.is(prevSelection) && ($isTableSelection(selection) || $isTableSelection(prevSelection)) && tableObserver.tableSelection && !tableObserver.tableSelection.is(prevSelection)) {
|
|
2063
|
+
if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey) tableObserver.$updateTableTableSelection(selection);
|
|
2064
|
+
else if (!$isTableSelection(selection) && $isTableSelection(prevSelection) && prevSelection.tableKey === tableObserver.tableNodeKey) tableObserver.$updateTableTableSelection(null);
|
|
2065
|
+
}
|
|
2066
|
+
if (tableObserver.hasHijackedSelectionStyles && !tableNode.isSelected()) $removeHighlightStyleToTable(editor, tableObserver);
|
|
2067
|
+
else if (!tableObserver.hasHijackedSelectionStyles && tableNode.isSelected()) $addHighlightStyleToTable(editor, tableObserver);
|
|
2068
|
+
}
|
|
2069
|
+
function detachTableObserverFromTableElement(tableElement, tableObserver) {
|
|
2070
|
+
if (getTableObserverFromTableElement(tableElement) === tableObserver) delete tableElement[LEXICAL_ELEMENT_KEY];
|
|
2071
|
+
}
|
|
2072
|
+
function attachTableObserverToTableElement(tableElement, tableObserver) {
|
|
2073
|
+
if (!(getTableObserverFromTableElement(tableElement) === null)) formatDevErrorMessage(`tableElement already has an attached TableObserver`);
|
|
2074
|
+
tableElement[LEXICAL_ELEMENT_KEY] = tableObserver;
|
|
2075
|
+
}
|
|
2076
|
+
function getTableObserverFromTableElement(tableElement) {
|
|
2077
|
+
return tableElement[LEXICAL_ELEMENT_KEY] || null;
|
|
2078
|
+
}
|
|
2079
|
+
function getTableObserverFromCellNode(node) {
|
|
2080
|
+
const cellNode = getDOMCellFromTarget(node);
|
|
2081
|
+
if (cellNode === null) return null;
|
|
2082
|
+
let currentNode = cellNode.elem;
|
|
2083
|
+
while (currentNode != null) {
|
|
2084
|
+
if (currentNode.nodeName === "TABLE" && LEXICAL_ELEMENT_KEY in currentNode && !!currentNode[LEXICAL_ELEMENT_KEY]) return {
|
|
2085
|
+
cellElement: cellNode,
|
|
2086
|
+
tableElement: currentNode,
|
|
2087
|
+
tableObserver: currentNode[LEXICAL_ELEMENT_KEY]
|
|
2088
|
+
};
|
|
2089
|
+
currentNode = currentNode.parentNode;
|
|
2090
|
+
}
|
|
2091
|
+
return null;
|
|
2092
|
+
}
|
|
2093
|
+
function getDOMCellFromTarget(node) {
|
|
2094
|
+
let currentNode = node;
|
|
2095
|
+
while (currentNode != null) {
|
|
2096
|
+
const nodeName = currentNode.nodeName;
|
|
2097
|
+
if (nodeName === "TD" || nodeName === "TH") {
|
|
2098
|
+
const cell = currentNode._cell;
|
|
2099
|
+
if (cell === void 0) return null;
|
|
2100
|
+
return cell;
|
|
2101
|
+
}
|
|
2102
|
+
currentNode = currentNode.parentNode;
|
|
2103
|
+
}
|
|
2104
|
+
return null;
|
|
2105
|
+
}
|
|
2106
|
+
function getDOMCellInTableFromTarget(table, node) {
|
|
2107
|
+
if (!table.contains(node)) return null;
|
|
2108
|
+
let cell = null;
|
|
2109
|
+
for (let currentNode = node; currentNode != null; currentNode = currentNode.parentNode) {
|
|
2110
|
+
if (currentNode === table) return cell;
|
|
2111
|
+
const nodeName = currentNode.nodeName;
|
|
2112
|
+
if (nodeName === "TD" || nodeName === "TH") cell = currentNode._cell || null;
|
|
2113
|
+
}
|
|
2114
|
+
return null;
|
|
2115
|
+
}
|
|
2116
|
+
function getTable(tableNode, dom) {
|
|
2117
|
+
const tableElement = getTableElement(tableNode, dom);
|
|
2118
|
+
const domRows = [];
|
|
2119
|
+
const grid = {
|
|
2120
|
+
columns: 0,
|
|
2121
|
+
domRows,
|
|
2122
|
+
rows: 0
|
|
2123
|
+
};
|
|
2124
|
+
let currentNode = tableElement.querySelector("tr");
|
|
2125
|
+
let x = 0;
|
|
2126
|
+
let y = 0;
|
|
2127
|
+
domRows.length = 0;
|
|
2128
|
+
while (currentNode != null) {
|
|
2129
|
+
const nodeMame = currentNode.nodeName;
|
|
2130
|
+
if (nodeMame === "TD" || nodeMame === "TH") {
|
|
2131
|
+
const elem = currentNode;
|
|
2132
|
+
const cell = {
|
|
2133
|
+
elem,
|
|
2134
|
+
hasBackgroundColor: elem.style.backgroundColor !== "",
|
|
2135
|
+
highlighted: false,
|
|
2136
|
+
x,
|
|
2137
|
+
y
|
|
2138
|
+
};
|
|
2139
|
+
currentNode._cell = cell;
|
|
2140
|
+
let row = domRows[y];
|
|
2141
|
+
if (row === void 0) row = domRows[y] = [];
|
|
2142
|
+
row[x] = cell;
|
|
2143
|
+
} else {
|
|
2144
|
+
const child = currentNode.firstChild;
|
|
2145
|
+
if (child != null) {
|
|
2146
|
+
currentNode = child;
|
|
2147
|
+
continue;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
const sibling = currentNode.nextSibling;
|
|
2151
|
+
if (sibling != null) {
|
|
2152
|
+
x++;
|
|
2153
|
+
currentNode = sibling;
|
|
2154
|
+
continue;
|
|
2155
|
+
}
|
|
2156
|
+
const parent = currentNode.parentNode;
|
|
2157
|
+
if (parent != null) {
|
|
2158
|
+
const parentSibling = parent.nextSibling;
|
|
2159
|
+
if (parentSibling == null) break;
|
|
2160
|
+
y++;
|
|
2161
|
+
x = 0;
|
|
2162
|
+
currentNode = parentSibling;
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
grid.columns = x + 1;
|
|
2166
|
+
grid.rows = y + 1;
|
|
2167
|
+
return grid;
|
|
2168
|
+
}
|
|
2169
|
+
function $updateDOMForSelection(editor, table, selection) {
|
|
2170
|
+
const selectedCellNodes = new Set(selection ? selection.getNodes() : []);
|
|
2171
|
+
$forEachTableCell(table, (cell, lexicalNode) => {
|
|
2172
|
+
const elem = cell.elem;
|
|
2173
|
+
if (selectedCellNodes.has(lexicalNode)) {
|
|
2174
|
+
cell.highlighted = true;
|
|
2175
|
+
$addHighlightToDOM(editor, cell);
|
|
2176
|
+
} else {
|
|
2177
|
+
cell.highlighted = false;
|
|
2178
|
+
$removeHighlightFromDOM(editor, cell);
|
|
2179
|
+
if (!elem.getAttribute("style")) elem.removeAttribute("style");
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
}
|
|
2183
|
+
function $forEachTableCell(grid, cb) {
|
|
2184
|
+
const { domRows } = grid;
|
|
2185
|
+
for (let y = 0; y < domRows.length; y++) {
|
|
2186
|
+
const row = domRows[y];
|
|
2187
|
+
if (!row) continue;
|
|
2188
|
+
for (let x = 0; x < row.length; x++) {
|
|
2189
|
+
const cell = row[x];
|
|
2190
|
+
if (!cell) continue;
|
|
2191
|
+
const lexicalNode = $getNearestNodeFromDOMNode(cell.elem);
|
|
2192
|
+
if (lexicalNode !== null) cb(cell, lexicalNode, {
|
|
2193
|
+
x,
|
|
2194
|
+
y
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
function $addHighlightStyleToTable(editor, tableSelection) {
|
|
2200
|
+
tableSelection.$disableHighlightStyle();
|
|
2201
|
+
$forEachTableCell(tableSelection.table, (cell) => {
|
|
2202
|
+
cell.highlighted = true;
|
|
2203
|
+
$addHighlightToDOM(editor, cell);
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
function $removeHighlightStyleToTable(editor, tableObserver) {
|
|
2207
|
+
tableObserver.$enableHighlightStyle();
|
|
2208
|
+
$forEachTableCell(tableObserver.table, (cell) => {
|
|
2209
|
+
const elem = cell.elem;
|
|
2210
|
+
cell.highlighted = false;
|
|
2211
|
+
$removeHighlightFromDOM(editor, cell);
|
|
2212
|
+
if (!elem.getAttribute("style")) elem.removeAttribute("style");
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
function $selectAdjacentCell(tableCellNode, direction) {
|
|
2216
|
+
const siblingMethod = direction === "next" ? "getNextSibling" : "getPreviousSibling";
|
|
2217
|
+
const childMethod = direction === "next" ? "getFirstChild" : "getLastChild";
|
|
2218
|
+
const sibling = tableCellNode[siblingMethod]();
|
|
2219
|
+
if ($isElementNode(sibling)) return sibling.selectEnd();
|
|
2220
|
+
const parentRow = $findMatchingParent(tableCellNode, $isTableRowNode);
|
|
2221
|
+
if (!(parentRow !== null)) formatDevErrorMessage(`selectAdjacentCell: Cell not in table row`);
|
|
2222
|
+
for (let nextRow = parentRow[siblingMethod](); $isTableRowNode(nextRow); nextRow = nextRow[siblingMethod]()) {
|
|
2223
|
+
const child = nextRow[childMethod]();
|
|
2224
|
+
if ($isElementNode(child)) return child.selectEnd();
|
|
2225
|
+
}
|
|
2226
|
+
const parentTable = $findMatchingParent(parentRow, $isTableNode);
|
|
2227
|
+
if (!(parentTable !== null)) formatDevErrorMessage(`selectAdjacentCell: Row not in table`);
|
|
2228
|
+
return direction === "next" ? parentTable.selectNext() : parentTable.selectPrevious();
|
|
2229
|
+
}
|
|
2230
|
+
const selectTableNodeInDirection = (tableObserver, tableNode, x, y, direction) => {
|
|
2231
|
+
const isForward = direction === "forward";
|
|
2232
|
+
switch (direction) {
|
|
2233
|
+
case "backward":
|
|
2234
|
+
case "forward":
|
|
2235
|
+
if (x !== (isForward ? tableObserver.table.columns - 1 : 0)) selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableObserver.table), isForward);
|
|
2236
|
+
else if (y !== (isForward ? tableObserver.table.rows - 1 : 0)) selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : tableObserver.table.columns - 1, y + (isForward ? 1 : -1), tableObserver.table), isForward);
|
|
2237
|
+
else if (!isForward) tableNode.selectPrevious();
|
|
2238
|
+
else tableNode.selectNext();
|
|
2239
|
+
return true;
|
|
2240
|
+
case "up":
|
|
2241
|
+
if (y !== 0) selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y - 1, tableObserver.table), false);
|
|
2242
|
+
else tableNode.selectPrevious();
|
|
2243
|
+
return true;
|
|
2244
|
+
case "down":
|
|
2245
|
+
if (y !== tableObserver.table.rows - 1) selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y + 1, tableObserver.table), true);
|
|
2246
|
+
else tableNode.selectNext();
|
|
2247
|
+
return true;
|
|
2248
|
+
default: return false;
|
|
2249
|
+
}
|
|
2250
|
+
};
|
|
2251
|
+
function getCorner(rect, cellValue) {
|
|
2252
|
+
let colName;
|
|
2253
|
+
let rowName;
|
|
2254
|
+
if (cellValue.startColumn === rect.minColumn) colName = "minColumn";
|
|
2255
|
+
else if (cellValue.startColumn + cellValue.cell.__colSpan - 1 === rect.maxColumn) colName = "maxColumn";
|
|
2256
|
+
else return null;
|
|
2257
|
+
if (cellValue.startRow === rect.minRow) rowName = "minRow";
|
|
2258
|
+
else if (cellValue.startRow + cellValue.cell.__rowSpan - 1 === rect.maxRow) rowName = "maxRow";
|
|
2259
|
+
else return null;
|
|
2260
|
+
return [colName, rowName];
|
|
2261
|
+
}
|
|
2262
|
+
function getCornerOrThrow(rect, cellValue) {
|
|
2263
|
+
const corner = getCorner(rect, cellValue);
|
|
2264
|
+
if (!(corner !== null)) formatDevErrorMessage(`getCornerOrThrow: cell ${cellValue.cell.getKey()} is not at a corner of rect`);
|
|
2265
|
+
return corner;
|
|
2266
|
+
}
|
|
2267
|
+
function oppositeCorner([colName, rowName]) {
|
|
2268
|
+
return [colName === "minColumn" ? "maxColumn" : "minColumn", rowName === "minRow" ? "maxRow" : "minRow"];
|
|
2269
|
+
}
|
|
2270
|
+
function cellAtCornerOrThrow(tableMap, rect, [colName, rowName]) {
|
|
2271
|
+
const rowNum = rect[rowName];
|
|
2272
|
+
const rowMap = tableMap[rowNum];
|
|
2273
|
+
if (!(rowMap !== void 0)) formatDevErrorMessage(`cellAtCornerOrThrow: ${rowName} = ${String(rowNum)} missing in tableMap`);
|
|
2274
|
+
const colNum = rect[colName];
|
|
2275
|
+
const cell = rowMap[colNum];
|
|
2276
|
+
if (!(cell !== void 0)) formatDevErrorMessage(`cellAtCornerOrThrow: ${colName} = ${String(colNum)} missing in tableMap`);
|
|
2277
|
+
return cell;
|
|
2278
|
+
}
|
|
2279
|
+
function $extractRectCorners(tableMap, anchorCellValue, newFocusCellValue) {
|
|
2280
|
+
const rect = $computeTableCellRectBoundary(tableMap, anchorCellValue, newFocusCellValue);
|
|
2281
|
+
const anchorCorner = getCorner(rect, anchorCellValue);
|
|
2282
|
+
if (anchorCorner) return [cellAtCornerOrThrow(tableMap, rect, anchorCorner), cellAtCornerOrThrow(tableMap, rect, oppositeCorner(anchorCorner))];
|
|
2283
|
+
const newFocusCorner = getCorner(rect, newFocusCellValue);
|
|
2284
|
+
if (newFocusCorner) return [cellAtCornerOrThrow(tableMap, rect, oppositeCorner(newFocusCorner)), cellAtCornerOrThrow(tableMap, rect, newFocusCorner)];
|
|
2285
|
+
const newAnchorCorner = ["minColumn", "minRow"];
|
|
2286
|
+
return [cellAtCornerOrThrow(tableMap, rect, newAnchorCorner), cellAtCornerOrThrow(tableMap, rect, oppositeCorner(newAnchorCorner))];
|
|
2287
|
+
}
|
|
2288
|
+
function $adjustFocusInDirection(tableObserver, tableMap, anchorCellValue, focusCellValue, direction) {
|
|
2289
|
+
const rect = $computeTableCellRectBoundary(tableMap, anchorCellValue, focusCellValue);
|
|
2290
|
+
const { topSpan, leftSpan, bottomSpan, rightSpan } = $computeTableCellRectSpans(tableMap, rect);
|
|
2291
|
+
const [focusColumn, focusRow] = oppositeCorner(getCornerOrThrow(rect, anchorCellValue));
|
|
2292
|
+
let fCol = rect[focusColumn];
|
|
2293
|
+
let fRow = rect[focusRow];
|
|
2294
|
+
if (direction === "forward") fCol += focusColumn === "maxColumn" ? 1 : leftSpan;
|
|
2295
|
+
else if (direction === "backward") fCol -= focusColumn === "minColumn" ? 1 : rightSpan;
|
|
2296
|
+
else if (direction === "down") fRow += focusRow === "maxRow" ? 1 : topSpan;
|
|
2297
|
+
else if (direction === "up") fRow -= focusRow === "minRow" ? 1 : bottomSpan;
|
|
2298
|
+
const targetRowMap = tableMap[fRow];
|
|
2299
|
+
if (targetRowMap === void 0) return false;
|
|
2300
|
+
const newFocusCellValue = targetRowMap[fCol];
|
|
2301
|
+
if (newFocusCellValue === void 0) return false;
|
|
2302
|
+
const [finalAnchorCell, finalFocusCell] = $extractRectCorners(tableMap, anchorCellValue, newFocusCellValue);
|
|
2303
|
+
const anchorDOM = $getObserverCellFromCellNodeOrThrow(tableObserver, finalAnchorCell.cell);
|
|
2304
|
+
const focusDOM = $getObserverCellFromCellNodeOrThrow(tableObserver, finalFocusCell.cell);
|
|
2305
|
+
tableObserver.$setAnchorCellForSelection(anchorDOM);
|
|
2306
|
+
tableObserver.$setFocusCellForSelection(focusDOM, true);
|
|
2307
|
+
return true;
|
|
2308
|
+
}
|
|
2309
|
+
function $isSelectionInTable(selection, tableNode) {
|
|
2310
|
+
if ($isRangeSelection(selection) || $isTableSelection(selection)) {
|
|
2311
|
+
const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode());
|
|
2312
|
+
const isFocusInside = tableNode.isParentOf(selection.focus.getNode());
|
|
2313
|
+
return isAnchorInside && isFocusInside;
|
|
2314
|
+
}
|
|
2315
|
+
return false;
|
|
2316
|
+
}
|
|
2317
|
+
function $isFullTableSelection(selection, tableNode) {
|
|
2318
|
+
if ($isTableSelection(selection)) {
|
|
2319
|
+
const anchorNode = selection.anchor.getNode();
|
|
2320
|
+
const focusNode = selection.focus.getNode();
|
|
2321
|
+
if (tableNode && anchorNode && focusNode) {
|
|
2322
|
+
const [map] = $computeTableMap(tableNode, anchorNode, focusNode);
|
|
2323
|
+
return anchorNode.getKey() === map[0][0].cell.getKey() && focusNode.getKey() === map[map.length - 1].at(-1).cell.getKey();
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
return false;
|
|
2327
|
+
}
|
|
2328
|
+
function selectTableCellNode(tableCell, fromStart) {
|
|
2329
|
+
if (fromStart) tableCell.selectStart();
|
|
2330
|
+
else tableCell.selectEnd();
|
|
2331
|
+
}
|
|
2332
|
+
function $addHighlightToDOM(editor, cell) {
|
|
2333
|
+
const element = cell.elem;
|
|
2334
|
+
const editorThemeClasses = editor._config.theme;
|
|
2335
|
+
if (!$isTableCellNode($getNearestNodeFromDOMNode(element))) formatDevErrorMessage(`Expected to find LexicalNode from Table Cell DOMNode`);
|
|
2336
|
+
addClassNamesToElement(element, editorThemeClasses.tableCellSelected);
|
|
2337
|
+
}
|
|
2338
|
+
function $removeHighlightFromDOM(editor, cell) {
|
|
2339
|
+
const element = cell.elem;
|
|
2340
|
+
if (!$isTableCellNode($getNearestNodeFromDOMNode(element))) formatDevErrorMessage(`Expected to find LexicalNode from Table Cell DOMNode`);
|
|
2341
|
+
const editorThemeClasses = editor._config.theme;
|
|
2342
|
+
removeClassNamesFromElement(element, editorThemeClasses.tableCellSelected);
|
|
2343
|
+
}
|
|
2344
|
+
function $findCellNode(node) {
|
|
2345
|
+
const cellNode = $findMatchingParent(node, $isTableCellNode);
|
|
2346
|
+
return $isTableCellNode(cellNode) ? cellNode : null;
|
|
2347
|
+
}
|
|
2348
|
+
function $findTableNode(node) {
|
|
2349
|
+
const tableNode = $findMatchingParent(node, $isTableNode);
|
|
2350
|
+
return $isTableNode(tableNode) ? tableNode : null;
|
|
2351
|
+
}
|
|
2352
|
+
function $getBlockParentIfFirstNode(node) {
|
|
2353
|
+
for (let prevNode = node, currentNode = node; currentNode !== null; prevNode = currentNode, currentNode = currentNode.getParent()) if ($isElementNode(currentNode)) {
|
|
2354
|
+
if (currentNode !== prevNode && currentNode.getFirstChild() !== prevNode) return null;
|
|
2355
|
+
else if (!currentNode.isInline()) return currentNode;
|
|
2356
|
+
}
|
|
2357
|
+
return null;
|
|
2358
|
+
}
|
|
2359
|
+
function $handleHorizontalArrowKeyRangeSelection(editor, event, selection, alter, isBackward, tableNode, tableObserver) {
|
|
2360
|
+
const initialFocus = $caretFromPoint(selection.focus, isBackward ? "previous" : "next");
|
|
2361
|
+
if ($isExtendableTextPointCaret(initialFocus)) return false;
|
|
2362
|
+
let lastCaret = initialFocus;
|
|
2363
|
+
for (const nextCaret of $extendCaretToRange(initialFocus).iterNodeCarets("shadowRoot")) {
|
|
2364
|
+
if (!($isSiblingCaret(nextCaret) && $isElementNode(nextCaret.origin))) return false;
|
|
2365
|
+
lastCaret = nextCaret;
|
|
2366
|
+
}
|
|
2367
|
+
const lastCaretParent = lastCaret.getParentAtCaret();
|
|
2368
|
+
if (!$isTableCellNode(lastCaretParent)) return false;
|
|
2369
|
+
const anchorCell = lastCaretParent;
|
|
2370
|
+
const focusCaret = $findNextTableCell($getSiblingCaret(anchorCell, lastCaret.direction));
|
|
2371
|
+
const anchorCellTable = $findMatchingParent(anchorCell, $isTableNode);
|
|
2372
|
+
if (!(anchorCellTable && anchorCellTable.is(tableNode))) return false;
|
|
2373
|
+
const anchorCellDOM = editor.getElementByKey(anchorCell.getKey());
|
|
2374
|
+
const anchorDOMCell = getDOMCellFromTarget(anchorCellDOM);
|
|
2375
|
+
if (!anchorCellDOM || !anchorDOMCell) return false;
|
|
2376
|
+
tableObserver.table = $getElementForTableNode(editor, anchorCellTable);
|
|
2377
|
+
if (!focusCaret) if (alter === "extend") {
|
|
2378
|
+
tableObserver.$setAnchorCellForSelection(anchorDOMCell);
|
|
2379
|
+
tableObserver.$setFocusCellForSelection(anchorDOMCell, true);
|
|
2380
|
+
} else {
|
|
2381
|
+
const outerFocusCaret = $getTableExitCaret($getSiblingCaret(anchorCellTable, initialFocus.direction));
|
|
2382
|
+
$setPointFromCaret(selection.anchor, outerFocusCaret);
|
|
2383
|
+
$setPointFromCaret(selection.focus, outerFocusCaret);
|
|
2384
|
+
}
|
|
2385
|
+
else if (alter === "extend") {
|
|
2386
|
+
const focusDOMCell = getDOMCellFromTarget(editor.getElementByKey(focusCaret.origin.getKey()));
|
|
2387
|
+
if (!focusDOMCell) return false;
|
|
2388
|
+
tableObserver.$setAnchorCellForSelection(anchorDOMCell);
|
|
2389
|
+
tableObserver.$setFocusCellForSelection(focusDOMCell, true);
|
|
2390
|
+
} else {
|
|
2391
|
+
const innerFocusCaret = $normalizeCaret(focusCaret);
|
|
2392
|
+
$setPointFromCaret(selection.anchor, innerFocusCaret);
|
|
2393
|
+
$setPointFromCaret(selection.focus, innerFocusCaret);
|
|
2394
|
+
}
|
|
2395
|
+
stopEvent(event);
|
|
2396
|
+
return true;
|
|
2397
|
+
}
|
|
2398
|
+
function $getTableExitCaret(initialCaret) {
|
|
2399
|
+
const adjacent = $getAdjacentChildCaret(initialCaret);
|
|
2400
|
+
return $isChildCaret(adjacent) ? $normalizeCaret(adjacent) : initialCaret;
|
|
2401
|
+
}
|
|
2402
|
+
function $findNextTableCell(initialCaret) {
|
|
2403
|
+
for (const nextCaret of $extendCaretToRange(initialCaret).iterNodeCarets("root")) {
|
|
2404
|
+
const { origin } = nextCaret;
|
|
2405
|
+
if ($isTableCellNode(origin)) {
|
|
2406
|
+
if ($isChildCaret(nextCaret)) return $getChildCaret(origin, initialCaret.direction);
|
|
2407
|
+
} else if (!$isTableRowNode(origin)) break;
|
|
2408
|
+
}
|
|
2409
|
+
return null;
|
|
2410
|
+
}
|
|
2411
|
+
function $handleArrowKey(editor, event, direction, tableNode, tableObserver, tableObservers) {
|
|
2412
|
+
if ((direction === "up" || direction === "down") && isTypeaheadMenuInView(editor)) return false;
|
|
2413
|
+
const selection = $getSelection();
|
|
2414
|
+
if (!$isSelectionInTable(selection, tableNode)) {
|
|
2415
|
+
if ($isRangeSelection(selection)) {
|
|
2416
|
+
if (direction === "backward") {
|
|
2417
|
+
if (selection.focus.offset > 0) return false;
|
|
2418
|
+
const parentNode = $getBlockParentIfFirstNode(selection.focus.getNode());
|
|
2419
|
+
if (!parentNode) return false;
|
|
2420
|
+
const siblingNode = parentNode.getPreviousSibling();
|
|
2421
|
+
if (!$isTableNode(siblingNode)) return false;
|
|
2422
|
+
stopEvent(event);
|
|
2423
|
+
if (event.shiftKey) selection.focus.set(siblingNode.getParentOrThrow().getKey(), siblingNode.getIndexWithinParent(), "element");
|
|
2424
|
+
else siblingNode.selectEnd();
|
|
2425
|
+
return true;
|
|
2426
|
+
} else if (event.shiftKey && (direction === "up" || direction === "down")) {
|
|
2427
|
+
const focusNode = selection.focus.getNode();
|
|
2428
|
+
if (!selection.isCollapsed() && (direction === "up" && !selection.isBackward() || direction === "down" && selection.isBackward())) {
|
|
2429
|
+
let focusParentNode = $findMatchingParent(focusNode, (n) => $isTableNode(n));
|
|
2430
|
+
if ($isTableCellNode(focusParentNode)) focusParentNode = $findMatchingParent(focusParentNode, $isTableNode);
|
|
2431
|
+
if (focusParentNode !== tableNode) return false;
|
|
2432
|
+
if (!focusParentNode) return false;
|
|
2433
|
+
const sibling = direction === "down" ? focusParentNode.getNextSibling() : focusParentNode.getPreviousSibling();
|
|
2434
|
+
if (!sibling) return false;
|
|
2435
|
+
let newOffset = 0;
|
|
2436
|
+
if (direction === "up") {
|
|
2437
|
+
if ($isElementNode(sibling)) newOffset = sibling.getChildrenSize();
|
|
2438
|
+
}
|
|
2439
|
+
let newFocusNode = sibling;
|
|
2440
|
+
if (direction === "up") {
|
|
2441
|
+
if ($isElementNode(sibling)) {
|
|
2442
|
+
const lastCell = sibling.getLastChild();
|
|
2443
|
+
newFocusNode = lastCell ? lastCell : sibling;
|
|
2444
|
+
newOffset = $isTextNode(newFocusNode) ? newFocusNode.getTextContentSize() : 0;
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
const newSelection = selection.clone();
|
|
2448
|
+
newSelection.focus.set(newFocusNode.getKey(), newOffset, $isTextNode(newFocusNode) ? "text" : "element");
|
|
2449
|
+
$setSelection(newSelection);
|
|
2450
|
+
stopEvent(event);
|
|
2451
|
+
return true;
|
|
2452
|
+
} else if ($isRootOrShadowRoot(focusNode)) {
|
|
2453
|
+
const selectedNode = direction === "up" ? selection.getNodes()[selection.getNodes().length - 1] : selection.getNodes()[0];
|
|
2454
|
+
if (selectedNode) {
|
|
2455
|
+
if ($findParentTableCellNodeInTable(tableNode, selectedNode) !== null) {
|
|
2456
|
+
const firstDescendant = tableNode.getFirstDescendant();
|
|
2457
|
+
const lastDescendant = tableNode.getLastDescendant();
|
|
2458
|
+
if (!firstDescendant || !lastDescendant) return false;
|
|
2459
|
+
const [firstCellNode] = $getNodeTriplet(firstDescendant);
|
|
2460
|
+
const [lastCellNode] = $getNodeTriplet(lastDescendant);
|
|
2461
|
+
const firstCellCoords = tableNode.getCordsFromCellNode(firstCellNode, tableObserver.table);
|
|
2462
|
+
const lastCellCoords = tableNode.getCordsFromCellNode(lastCellNode, tableObserver.table);
|
|
2463
|
+
const firstCellDOM = tableNode.getDOMCellFromCordsOrThrow(firstCellCoords.x, firstCellCoords.y, tableObserver.table);
|
|
2464
|
+
const lastCellDOM = tableNode.getDOMCellFromCordsOrThrow(lastCellCoords.x, lastCellCoords.y, tableObserver.table);
|
|
2465
|
+
tableObserver.$setAnchorCellForSelection(firstCellDOM);
|
|
2466
|
+
tableObserver.$setFocusCellForSelection(lastCellDOM, true);
|
|
2467
|
+
return true;
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
return false;
|
|
2471
|
+
} else {
|
|
2472
|
+
let focusParentNode = $findMatchingParent(focusNode, (n) => $isElementNode(n) && !n.isInline());
|
|
2473
|
+
if ($isTableCellNode(focusParentNode)) focusParentNode = $findMatchingParent(focusParentNode, $isTableNode);
|
|
2474
|
+
if (!focusParentNode) return false;
|
|
2475
|
+
const sibling = direction === "down" ? focusParentNode.getNextSibling() : focusParentNode.getPreviousSibling();
|
|
2476
|
+
if ($isTableNode(sibling) && tableObserver.tableNodeKey === sibling.getKey()) {
|
|
2477
|
+
const firstDescendant = sibling.getFirstDescendant();
|
|
2478
|
+
const lastDescendant = sibling.getLastDescendant();
|
|
2479
|
+
if (!firstDescendant || !lastDescendant) return false;
|
|
2480
|
+
const [firstCellNode] = $getNodeTriplet(firstDescendant);
|
|
2481
|
+
const [lastCellNode] = $getNodeTriplet(lastDescendant);
|
|
2482
|
+
const newSelection = selection.clone();
|
|
2483
|
+
newSelection.focus.set((direction === "up" ? firstCellNode : lastCellNode).getKey(), direction === "up" ? 0 : lastCellNode.getChildrenSize(), "element");
|
|
2484
|
+
stopEvent(event);
|
|
2485
|
+
$setSelection(newSelection);
|
|
2486
|
+
return true;
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
if (direction === "down" && $isScrollableTablesActive(editor)) tableObservers.setShouldCheckSelectionForTable(tableNode.getKey());
|
|
2492
|
+
return false;
|
|
2493
|
+
}
|
|
2494
|
+
if ($isRangeSelection(selection)) {
|
|
2495
|
+
if (direction === "backward" || direction === "forward") return $handleHorizontalArrowKeyRangeSelection(editor, event, selection, event.shiftKey ? "extend" : "move", direction === "backward", tableNode, tableObserver);
|
|
2496
|
+
if (selection.isCollapsed()) {
|
|
2497
|
+
const { anchor, focus } = selection;
|
|
2498
|
+
const anchorCellNode = $findMatchingParent(anchor.getNode(), $isTableCellNode);
|
|
2499
|
+
const focusCellNode = $findMatchingParent(focus.getNode(), $isTableCellNode);
|
|
2500
|
+
if (!$isTableCellNode(anchorCellNode) || !anchorCellNode.is(focusCellNode)) return false;
|
|
2501
|
+
const anchorCellTable = $findTableNode(anchorCellNode);
|
|
2502
|
+
if (anchorCellTable !== tableNode && anchorCellTable != null) {
|
|
2503
|
+
const anchorCellTableElement = getTableElement(anchorCellTable, editor.getElementByKey(anchorCellTable.getKey()));
|
|
2504
|
+
if (anchorCellTableElement != null) {
|
|
2505
|
+
tableObserver.table = getTable(anchorCellTable, anchorCellTableElement);
|
|
2506
|
+
return $handleArrowKey(editor, event, direction, anchorCellTable, tableObserver, tableObservers);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
const anchorCellDom = editor.getElementByKey(anchorCellNode.__key);
|
|
2510
|
+
const anchorDOM = editor.getElementByKey(anchor.key);
|
|
2511
|
+
if (anchorDOM == null || anchorCellDom == null) return false;
|
|
2512
|
+
let edgeSelectionRect;
|
|
2513
|
+
if (anchor.type === "element") edgeSelectionRect = anchorDOM.getBoundingClientRect();
|
|
2514
|
+
else {
|
|
2515
|
+
const domSelection = getDOMSelection(getEditorWindow(editor));
|
|
2516
|
+
if (domSelection === null || domSelection.rangeCount === 0) return false;
|
|
2517
|
+
edgeSelectionRect = domSelection.getRangeAt(0).getBoundingClientRect();
|
|
2518
|
+
}
|
|
2519
|
+
const edgeChild = direction === "up" ? anchorCellNode.getFirstChild() : anchorCellNode.getLastChild();
|
|
2520
|
+
if (edgeChild == null) return false;
|
|
2521
|
+
const edgeChildDOM = editor.getElementByKey(edgeChild.__key);
|
|
2522
|
+
if (edgeChildDOM == null) return false;
|
|
2523
|
+
const edgeRect = edgeChildDOM.getBoundingClientRect();
|
|
2524
|
+
if (direction === "up" ? edgeRect.top > edgeSelectionRect.top - edgeSelectionRect.height : edgeSelectionRect.bottom + edgeSelectionRect.height > edgeRect.bottom) {
|
|
2525
|
+
stopEvent(event);
|
|
2526
|
+
const cords = tableNode.getCordsFromCellNode(anchorCellNode, tableObserver.table);
|
|
2527
|
+
if (event.shiftKey) {
|
|
2528
|
+
const cell = tableNode.getDOMCellFromCordsOrThrow(cords.x, cords.y, tableObserver.table);
|
|
2529
|
+
tableObserver.$setAnchorCellForSelection(cell);
|
|
2530
|
+
tableObserver.$setFocusCellForSelection(cell, true);
|
|
2531
|
+
} else return selectTableNodeInDirection(tableObserver, tableNode, cords.x, cords.y, direction);
|
|
2532
|
+
return true;
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
} else if ($isTableSelection(selection)) {
|
|
2536
|
+
const { anchor, focus } = selection;
|
|
2537
|
+
const anchorCellNode = $findMatchingParent(anchor.getNode(), $isTableCellNode);
|
|
2538
|
+
const focusCellNode = $findMatchingParent(focus.getNode(), $isTableCellNode);
|
|
2539
|
+
const [tableNodeFromSelection] = selection.getNodes();
|
|
2540
|
+
if (!$isTableNode(tableNodeFromSelection)) formatDevErrorMessage(`$handleArrowKey: TableSelection.getNodes()[0] expected to be TableNode`);
|
|
2541
|
+
const tableElement = getTableElement(tableNodeFromSelection, editor.getElementByKey(tableNodeFromSelection.getKey()));
|
|
2542
|
+
if (!$isTableCellNode(anchorCellNode) || !$isTableCellNode(focusCellNode) || !$isTableNode(tableNodeFromSelection) || tableElement == null) return false;
|
|
2543
|
+
tableObserver.$updateTableTableSelection(selection);
|
|
2544
|
+
const grid = getTable(tableNodeFromSelection, tableElement);
|
|
2545
|
+
const cordsAnchor = tableNode.getCordsFromCellNode(anchorCellNode, grid);
|
|
2546
|
+
const anchorCell = tableNode.getDOMCellFromCordsOrThrow(cordsAnchor.x, cordsAnchor.y, grid);
|
|
2547
|
+
tableObserver.$setAnchorCellForSelection(anchorCell);
|
|
2548
|
+
stopEvent(event);
|
|
2549
|
+
if (event.shiftKey) {
|
|
2550
|
+
const [tableMap, anchorValue, focusValue] = $computeTableMap(tableNode, anchorCellNode, focusCellNode);
|
|
2551
|
+
return $adjustFocusInDirection(tableObserver, tableMap, anchorValue, focusValue, direction);
|
|
2552
|
+
} else focusCellNode.selectEnd();
|
|
2553
|
+
return true;
|
|
2554
|
+
}
|
|
2555
|
+
return false;
|
|
2556
|
+
}
|
|
2557
|
+
function stopEvent(event) {
|
|
2558
|
+
event.preventDefault();
|
|
2559
|
+
event.stopImmediatePropagation();
|
|
2560
|
+
event.stopPropagation();
|
|
2561
|
+
}
|
|
2562
|
+
function isTypeaheadMenuInView(editor) {
|
|
2563
|
+
const root = editor.getRootElement();
|
|
2564
|
+
if (!root) return false;
|
|
2565
|
+
return root.hasAttribute("aria-controls") && root.getAttribute("aria-controls") === "typeahead-menu";
|
|
2566
|
+
}
|
|
2567
|
+
function $insertParagraphAtTableEdge(edgePosition, tableNode, children) {
|
|
2568
|
+
const paragraphNode = $createParagraphNode();
|
|
2569
|
+
if (edgePosition === "first") tableNode.insertBefore(paragraphNode);
|
|
2570
|
+
else tableNode.insertAfter(paragraphNode);
|
|
2571
|
+
paragraphNode.append(...children || []);
|
|
2572
|
+
paragraphNode.selectEnd();
|
|
2573
|
+
}
|
|
2574
|
+
function $getTableEdgeCursorPosition(editor, selection, tableNode) {
|
|
2575
|
+
const tableNodeParent = tableNode.getParent();
|
|
2576
|
+
if (!tableNodeParent) return;
|
|
2577
|
+
const domSelection = getDOMSelection(getEditorWindow(editor));
|
|
2578
|
+
if (!domSelection) return;
|
|
2579
|
+
const domAnchorNode = domSelection.anchorNode;
|
|
2580
|
+
const tableNodeParentDOM = editor.getElementByKey(tableNodeParent.getKey());
|
|
2581
|
+
const tableElement = getTableElement(tableNode, editor.getElementByKey(tableNode.getKey()));
|
|
2582
|
+
if (!domAnchorNode || !tableNodeParentDOM || !tableElement || !tableNodeParentDOM.contains(domAnchorNode) || tableElement.contains(domAnchorNode)) return;
|
|
2583
|
+
const anchorCellNode = $findMatchingParent(selection.anchor.getNode(), (n) => $isTableCellNode(n));
|
|
2584
|
+
if (!anchorCellNode) return;
|
|
2585
|
+
const parentTable = $findMatchingParent(anchorCellNode, (n) => $isTableNode(n));
|
|
2586
|
+
if (!$isTableNode(parentTable) || !parentTable.is(tableNode)) return;
|
|
2587
|
+
const [tableMap, cellValue] = $computeTableMap(tableNode, anchorCellNode, anchorCellNode);
|
|
2588
|
+
const firstCell = tableMap[0][0];
|
|
2589
|
+
const lastCell = tableMap[tableMap.length - 1][tableMap[0].length - 1];
|
|
2590
|
+
const { startRow, startColumn } = cellValue;
|
|
2591
|
+
const isAtFirstCell = startRow === firstCell.startRow && startColumn === firstCell.startColumn;
|
|
2592
|
+
const isAtLastCell = startRow === lastCell.startRow && startColumn === lastCell.startColumn;
|
|
2593
|
+
if (isAtFirstCell) return "first";
|
|
2594
|
+
else if (isAtLastCell) return "last";
|
|
2595
|
+
else return;
|
|
2596
|
+
}
|
|
2597
|
+
function $getObserverCellFromCellNodeOrThrow(tableObserver, tableCellNode) {
|
|
2598
|
+
const { tableNode } = tableObserver.$lookup();
|
|
2599
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableObserver.table);
|
|
2600
|
+
return tableNode.getDOMCellFromCordsOrThrow(currentCords.x, currentCords.y, tableObserver.table);
|
|
2601
|
+
}
|
|
2602
|
+
function $getNearestTableCellInTableFromDOMNode(tableNode, startingDOM, editorState) {
|
|
2603
|
+
return $findParentTableCellNodeInTable(tableNode, $getNearestNodeFromDOMNode(startingDOM, editorState));
|
|
2604
|
+
}
|
|
2605
|
+
function isHTMLDivElement(element) {
|
|
2606
|
+
return isHTMLElement$1(element) && element.nodeName === "DIV";
|
|
2607
|
+
}
|
|
2608
|
+
function updateColgroup(dom, colCount, colWidths) {
|
|
2609
|
+
const colGroup = dom.querySelector("colgroup");
|
|
2610
|
+
if (!colGroup) return;
|
|
2611
|
+
const cols = [];
|
|
2612
|
+
for (let i = 0; i < colCount; i++) {
|
|
2613
|
+
const col = document.createElement("col");
|
|
2614
|
+
const width = colWidths && colWidths[i];
|
|
2615
|
+
if (width) col.style.width = `${width}px`;
|
|
2616
|
+
cols.push(col);
|
|
2617
|
+
}
|
|
2618
|
+
colGroup.replaceChildren(...cols);
|
|
2619
|
+
}
|
|
2620
|
+
function setRowStriping(dom, config, rowStriping) {
|
|
2621
|
+
if (rowStriping) {
|
|
2622
|
+
addClassNamesToElement(dom, config.theme.tableRowStriping);
|
|
2623
|
+
dom.setAttribute("data-lexical-row-striping", "true");
|
|
2624
|
+
} else {
|
|
2625
|
+
removeClassNamesFromElement(dom, config.theme.tableRowStriping);
|
|
2626
|
+
dom.removeAttribute("data-lexical-row-striping");
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
function setFrozenColumns(dom, tableElement, config, frozenColumnCount) {
|
|
2630
|
+
if (frozenColumnCount > 0) {
|
|
2631
|
+
addClassNamesToElement(dom, config.theme.tableFrozenColumn);
|
|
2632
|
+
tableElement.setAttribute("data-lexical-frozen-column", "true");
|
|
2633
|
+
} else {
|
|
2634
|
+
removeClassNamesFromElement(dom, config.theme.tableFrozenColumn);
|
|
2635
|
+
tableElement.removeAttribute("data-lexical-frozen-column");
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
function setFrozenRows(dom, tableElement, config, frozenRowCount) {
|
|
2639
|
+
if (frozenRowCount > 0) {
|
|
2640
|
+
addClassNamesToElement(dom, config.theme.tableFrozenRow);
|
|
2641
|
+
tableElement.setAttribute("data-lexical-frozen-row", "true");
|
|
2642
|
+
} else {
|
|
2643
|
+
removeClassNamesFromElement(dom, config.theme.tableFrozenRow);
|
|
2644
|
+
tableElement.removeAttribute("data-lexical-frozen-row");
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
function alignTableElement(dom, config, formatType) {
|
|
2648
|
+
if (!config.theme.tableAlignment) return;
|
|
2649
|
+
const removeClasses = [];
|
|
2650
|
+
const addClasses = [];
|
|
2651
|
+
for (const format of ["center", "right"]) {
|
|
2652
|
+
const classes = config.theme.tableAlignment[format];
|
|
2653
|
+
if (!classes) continue;
|
|
2654
|
+
(format === formatType ? addClasses : removeClasses).push(classes);
|
|
2655
|
+
}
|
|
2656
|
+
removeClassNamesFromElement(dom, ...removeClasses);
|
|
2657
|
+
addClassNamesToElement(dom, ...addClasses);
|
|
2658
|
+
}
|
|
2659
|
+
const scrollableEditors = /* @__PURE__ */ new WeakSet();
|
|
2660
|
+
function $isScrollableTablesActive(editor = $getEditor()) {
|
|
2661
|
+
return scrollableEditors.has(editor);
|
|
2662
|
+
}
|
|
2663
|
+
function setScrollableTablesActive(editor, active) {
|
|
2664
|
+
if (active) {
|
|
2665
|
+
if (!editor._config.theme.tableScrollableWrapper) console.warn("TableNode: hasHorizontalScroll is active but theme.tableScrollableWrapper is not defined.");
|
|
2666
|
+
scrollableEditors.add(editor);
|
|
2667
|
+
} else scrollableEditors.delete(editor);
|
|
2668
|
+
}
|
|
2669
|
+
/** @noInheritDoc */
|
|
2670
|
+
var TableNode = class TableNode extends ElementNode {
|
|
2671
|
+
/** @internal */
|
|
2672
|
+
__rowStriping;
|
|
2673
|
+
__frozenColumnCount;
|
|
2674
|
+
__frozenRowCount;
|
|
2675
|
+
__colWidths;
|
|
2676
|
+
static getType() {
|
|
2677
|
+
return "table";
|
|
2678
|
+
}
|
|
2679
|
+
getColWidths() {
|
|
2680
|
+
return this.getLatest().__colWidths;
|
|
2681
|
+
}
|
|
2682
|
+
setColWidths(colWidths) {
|
|
2683
|
+
const self = this.getWritable();
|
|
2684
|
+
self.__colWidths = colWidths !== void 0 && true ? Object.freeze(colWidths) : colWidths;
|
|
2685
|
+
return self;
|
|
2686
|
+
}
|
|
2687
|
+
static clone(node) {
|
|
2688
|
+
return new TableNode(node.__key);
|
|
2689
|
+
}
|
|
2690
|
+
afterCloneFrom(prevNode) {
|
|
2691
|
+
super.afterCloneFrom(prevNode);
|
|
2692
|
+
this.__colWidths = prevNode.__colWidths;
|
|
2693
|
+
this.__rowStriping = prevNode.__rowStriping;
|
|
2694
|
+
this.__frozenColumnCount = prevNode.__frozenColumnCount;
|
|
2695
|
+
this.__frozenRowCount = prevNode.__frozenRowCount;
|
|
2696
|
+
}
|
|
2697
|
+
static importDOM() {
|
|
2698
|
+
return { table: (_node) => ({
|
|
2699
|
+
conversion: $convertTableElement,
|
|
2700
|
+
priority: 1
|
|
2701
|
+
}) };
|
|
2702
|
+
}
|
|
2703
|
+
static importJSON(serializedNode) {
|
|
2704
|
+
return $createTableNode().updateFromJSON(serializedNode);
|
|
2705
|
+
}
|
|
2706
|
+
updateFromJSON(serializedNode) {
|
|
2707
|
+
return super.updateFromJSON(serializedNode).setRowStriping(serializedNode.rowStriping || false).setFrozenColumns(serializedNode.frozenColumnCount || 0).setFrozenRows(serializedNode.frozenRowCount || 0).setColWidths(serializedNode.colWidths);
|
|
2708
|
+
}
|
|
2709
|
+
constructor(key) {
|
|
2710
|
+
super(key);
|
|
2711
|
+
this.__rowStriping = false;
|
|
2712
|
+
this.__frozenColumnCount = 0;
|
|
2713
|
+
this.__frozenRowCount = 0;
|
|
2714
|
+
this.__colWidths = void 0;
|
|
2715
|
+
}
|
|
2716
|
+
exportJSON() {
|
|
2717
|
+
return {
|
|
2718
|
+
...super.exportJSON(),
|
|
2719
|
+
colWidths: this.getColWidths(),
|
|
2720
|
+
frozenColumnCount: this.__frozenColumnCount ? this.__frozenColumnCount : void 0,
|
|
2721
|
+
frozenRowCount: this.__frozenRowCount ? this.__frozenRowCount : void 0,
|
|
2722
|
+
rowStriping: this.__rowStriping ? this.__rowStriping : void 0
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
extractWithChild(child, selection, destination) {
|
|
2726
|
+
return destination === "html";
|
|
2727
|
+
}
|
|
2728
|
+
getDOMSlot(element) {
|
|
2729
|
+
const tableElement = !isHTMLTableElement(element) ? element.querySelector("table") : element;
|
|
2730
|
+
if (!isHTMLTableElement(tableElement)) formatDevErrorMessage(`TableNode.getDOMSlot: createDOM() did not return a table`);
|
|
2731
|
+
return super.getDOMSlot(element).withElement(tableElement).withAfter(tableElement.querySelector("colgroup"));
|
|
2732
|
+
}
|
|
2733
|
+
createDOM(config, editor) {
|
|
2734
|
+
const tableElement = document.createElement("table");
|
|
2735
|
+
if (this.__style) setDOMStyleFromCSS(tableElement.style, this.__style);
|
|
2736
|
+
const colGroup = document.createElement("colgroup");
|
|
2737
|
+
tableElement.appendChild(colGroup);
|
|
2738
|
+
setDOMUnmanaged(colGroup);
|
|
2739
|
+
addClassNamesToElement(tableElement, config.theme.table);
|
|
2740
|
+
this.updateTableElement(null, tableElement, config);
|
|
2741
|
+
if ($isScrollableTablesActive(editor)) {
|
|
2742
|
+
const wrapperElement = document.createElement("div");
|
|
2743
|
+
const classes = config.theme.tableScrollableWrapper;
|
|
2744
|
+
if (classes) addClassNamesToElement(wrapperElement, classes);
|
|
2745
|
+
else wrapperElement.style.overflowX = "auto";
|
|
2746
|
+
wrapperElement.appendChild(tableElement);
|
|
2747
|
+
this.updateTableWrapper(null, wrapperElement, tableElement, config);
|
|
2748
|
+
return wrapperElement;
|
|
2749
|
+
}
|
|
2750
|
+
return tableElement;
|
|
2751
|
+
}
|
|
2752
|
+
updateTableWrapper(prevNode, tableWrapper, tableElement, config) {
|
|
2753
|
+
if (this.__frozenColumnCount !== (prevNode ? prevNode.__frozenColumnCount : 0)) setFrozenColumns(tableWrapper, tableElement, config, this.__frozenColumnCount);
|
|
2754
|
+
if (this.__frozenRowCount !== (prevNode ? prevNode.__frozenRowCount : 0)) setFrozenRows(tableWrapper, tableElement, config, this.__frozenRowCount);
|
|
2755
|
+
}
|
|
2756
|
+
updateTableElement(prevNode, tableElement, config) {
|
|
2757
|
+
if (this.__style !== (prevNode ? prevNode.__style : "")) setDOMStyleFromCSS(tableElement.style, this.__style, prevNode ? prevNode.__style : "");
|
|
2758
|
+
if (this.__rowStriping !== (prevNode ? prevNode.__rowStriping : false)) setRowStriping(tableElement, config, this.__rowStriping);
|
|
2759
|
+
const prevColCount = prevNode ? prevNode.getColumnCount() : 0;
|
|
2760
|
+
const prevColWidths = prevNode ? prevNode.__colWidths : void 0;
|
|
2761
|
+
if (this.getColumnCount() !== prevColCount || this.getColWidths() !== prevColWidths) updateColgroup(tableElement, this.getColumnCount(), this.getColWidths());
|
|
2762
|
+
alignTableElement(tableElement, config, this.getFormatType());
|
|
2763
|
+
}
|
|
2764
|
+
updateDOM(prevNode, dom, config) {
|
|
2765
|
+
const tableElement = getTableElement(this, dom);
|
|
2766
|
+
if (dom === tableElement === $isScrollableTablesActive()) return true;
|
|
2767
|
+
if (isHTMLDivElement(dom)) this.updateTableWrapper(prevNode, dom, tableElement, config);
|
|
2768
|
+
this.updateTableElement(prevNode, tableElement, config);
|
|
2769
|
+
return false;
|
|
2770
|
+
}
|
|
2771
|
+
scaleDOMColWidths(dom, scale) {
|
|
2772
|
+
const colWidths = this.getColWidths();
|
|
2773
|
+
if (!colWidths) return;
|
|
2774
|
+
updateColgroup(getTableElement(this, dom), this.getColumnCount(), colWidths.map((width) => width * scale));
|
|
2775
|
+
}
|
|
2776
|
+
exportDOM(editor) {
|
|
2777
|
+
const superExport = super.exportDOM(editor);
|
|
2778
|
+
const { element } = superExport;
|
|
2779
|
+
return {
|
|
2780
|
+
after: (tableElement) => {
|
|
2781
|
+
if (superExport.after) tableElement = superExport.after(tableElement);
|
|
2782
|
+
if (!isHTMLTableElement(tableElement) && isHTMLElement$1(tableElement)) tableElement = tableElement.querySelector("table");
|
|
2783
|
+
if (!isHTMLTableElement(tableElement)) return null;
|
|
2784
|
+
alignTableElement(tableElement, editor._config, this.getFormatType());
|
|
2785
|
+
const [tableMap] = $computeTableMapSkipCellCheck(this, null, null);
|
|
2786
|
+
const cellValues = /* @__PURE__ */ new Map();
|
|
2787
|
+
for (const mapRow of tableMap) for (const mapValue of mapRow) {
|
|
2788
|
+
const key = mapValue.cell.getKey();
|
|
2789
|
+
if (!cellValues.has(key)) cellValues.set(key, {
|
|
2790
|
+
colSpan: mapValue.cell.getColSpan(),
|
|
2791
|
+
startColumn: mapValue.startColumn
|
|
2792
|
+
});
|
|
2793
|
+
}
|
|
2794
|
+
const knownColumns = /* @__PURE__ */ new Set();
|
|
2795
|
+
for (const cellDOM of tableElement.querySelectorAll(":scope > tr > [data-temporary-table-cell-lexical-key]")) {
|
|
2796
|
+
const key = cellDOM.getAttribute("data-temporary-table-cell-lexical-key");
|
|
2797
|
+
if (key) {
|
|
2798
|
+
const cellSpan = cellValues.get(key);
|
|
2799
|
+
cellDOM.removeAttribute("data-temporary-table-cell-lexical-key");
|
|
2800
|
+
if (cellSpan) {
|
|
2801
|
+
cellValues.delete(key);
|
|
2802
|
+
for (let i = 0; i < cellSpan.colSpan; i++) knownColumns.add(i + cellSpan.startColumn);
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
const colGroup = tableElement.querySelector(":scope > colgroup");
|
|
2807
|
+
if (colGroup) {
|
|
2808
|
+
const cols = Array.from(tableElement.querySelectorAll(":scope > colgroup > col")).filter((dom, i) => knownColumns.has(i));
|
|
2809
|
+
colGroup.replaceChildren(...cols);
|
|
2810
|
+
}
|
|
2811
|
+
const rows = tableElement.querySelectorAll(":scope > tr");
|
|
2812
|
+
if (rows.length > 0) {
|
|
2813
|
+
const tBody = document.createElement("tbody");
|
|
2814
|
+
for (const row of rows) tBody.appendChild(row);
|
|
2815
|
+
tableElement.append(tBody);
|
|
2816
|
+
}
|
|
2817
|
+
return tableElement;
|
|
2818
|
+
},
|
|
2819
|
+
element: !isHTMLTableElement(element) && isHTMLElement$1(element) ? element.querySelector("table") : element
|
|
2820
|
+
};
|
|
2821
|
+
}
|
|
2822
|
+
canBeEmpty() {
|
|
2823
|
+
return false;
|
|
2824
|
+
}
|
|
2825
|
+
isShadowRoot() {
|
|
2826
|
+
return true;
|
|
2827
|
+
}
|
|
2828
|
+
getCordsFromCellNode(tableCellNode, table) {
|
|
2829
|
+
const { rows, domRows } = table;
|
|
2830
|
+
for (let y = 0; y < rows; y++) {
|
|
2831
|
+
const row = domRows[y];
|
|
2832
|
+
if (row == null) continue;
|
|
2833
|
+
for (let x = 0; x < row.length; x++) {
|
|
2834
|
+
const cell = row[x];
|
|
2835
|
+
if (cell == null) continue;
|
|
2836
|
+
const { elem } = cell;
|
|
2837
|
+
const cellNode = $getNearestTableCellInTableFromDOMNode(this, elem);
|
|
2838
|
+
if (cellNode !== null && tableCellNode.is(cellNode)) return {
|
|
2839
|
+
x,
|
|
2840
|
+
y
|
|
2841
|
+
};
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
throw new Error("Cell not found in table.");
|
|
2845
|
+
}
|
|
2846
|
+
getDOMCellFromCords(x, y, table) {
|
|
2847
|
+
const { domRows } = table;
|
|
2848
|
+
const row = domRows[y];
|
|
2849
|
+
if (row == null) return null;
|
|
2850
|
+
const cell = row[x < row.length ? x : row.length - 1];
|
|
2851
|
+
if (cell == null) return null;
|
|
2852
|
+
return cell;
|
|
2853
|
+
}
|
|
2854
|
+
getDOMCellFromCordsOrThrow(x, y, table) {
|
|
2855
|
+
const cell = this.getDOMCellFromCords(x, y, table);
|
|
2856
|
+
if (!cell) throw new Error("Cell not found at cords.");
|
|
2857
|
+
return cell;
|
|
2858
|
+
}
|
|
2859
|
+
getCellNodeFromCords(x, y, table) {
|
|
2860
|
+
const cell = this.getDOMCellFromCords(x, y, table);
|
|
2861
|
+
if (cell == null) return null;
|
|
2862
|
+
const node = $getNearestNodeFromDOMNode(cell.elem);
|
|
2863
|
+
if ($isTableCellNode(node)) return node;
|
|
2864
|
+
return null;
|
|
2865
|
+
}
|
|
2866
|
+
getCellNodeFromCordsOrThrow(x, y, table) {
|
|
2867
|
+
const node = this.getCellNodeFromCords(x, y, table);
|
|
2868
|
+
if (!node) throw new Error("Node at cords not TableCellNode.");
|
|
2869
|
+
return node;
|
|
2870
|
+
}
|
|
2871
|
+
getRowStriping() {
|
|
2872
|
+
return Boolean(this.getLatest().__rowStriping);
|
|
2873
|
+
}
|
|
2874
|
+
setRowStriping(newRowStriping) {
|
|
2875
|
+
const self = this.getWritable();
|
|
2876
|
+
self.__rowStriping = newRowStriping;
|
|
2877
|
+
return self;
|
|
2878
|
+
}
|
|
2879
|
+
setFrozenColumns(columnCount) {
|
|
2880
|
+
const self = this.getWritable();
|
|
2881
|
+
self.__frozenColumnCount = columnCount;
|
|
2882
|
+
return self;
|
|
2883
|
+
}
|
|
2884
|
+
getFrozenColumns() {
|
|
2885
|
+
return this.getLatest().__frozenColumnCount;
|
|
2886
|
+
}
|
|
2887
|
+
setFrozenRows(rowCount) {
|
|
2888
|
+
const self = this.getWritable();
|
|
2889
|
+
self.__frozenRowCount = rowCount;
|
|
2890
|
+
return self;
|
|
2891
|
+
}
|
|
2892
|
+
getFrozenRows() {
|
|
2893
|
+
return this.getLatest().__frozenRowCount;
|
|
2894
|
+
}
|
|
2895
|
+
canSelectBefore() {
|
|
2896
|
+
return true;
|
|
2897
|
+
}
|
|
2898
|
+
canIndent() {
|
|
2899
|
+
return false;
|
|
2900
|
+
}
|
|
2901
|
+
getColumnCount() {
|
|
2902
|
+
const firstRow = this.getFirstChild();
|
|
2903
|
+
if (!firstRow) return 0;
|
|
2904
|
+
let columnCount = 0;
|
|
2905
|
+
firstRow.getChildren().forEach((cell) => {
|
|
2906
|
+
if ($isTableCellNode(cell)) columnCount += cell.getColSpan();
|
|
2907
|
+
});
|
|
2908
|
+
return columnCount;
|
|
2909
|
+
}
|
|
2910
|
+
};
|
|
2911
|
+
function $getElementForTableNode(editor, tableNode) {
|
|
2912
|
+
const tableElement = editor.getElementByKey(tableNode.getKey());
|
|
2913
|
+
if (!(tableElement !== null)) formatDevErrorMessage(`$getElementForTableNode: Table Element Not Found`);
|
|
2914
|
+
return getTable(tableNode, tableElement);
|
|
2915
|
+
}
|
|
2916
|
+
function $convertTableElement(domNode) {
|
|
2917
|
+
const tableNode = $createTableNode();
|
|
2918
|
+
if (domNode.hasAttribute("data-lexical-row-striping")) tableNode.setRowStriping(true);
|
|
2919
|
+
if (domNode.hasAttribute("data-lexical-frozen-column")) tableNode.setFrozenColumns(1);
|
|
2920
|
+
if (domNode.hasAttribute("data-lexical-frozen-row")) tableNode.setFrozenRows(1);
|
|
2921
|
+
const colGroup = domNode.querySelector(":scope > colgroup");
|
|
2922
|
+
if (colGroup) {
|
|
2923
|
+
let columns = [];
|
|
2924
|
+
for (const col of colGroup.querySelectorAll(":scope > col")) {
|
|
2925
|
+
let width = col.style.width || "";
|
|
2926
|
+
if (!PIXEL_VALUE_REG_EXP.test(width)) {
|
|
2927
|
+
width = col.getAttribute("width") || "";
|
|
2928
|
+
if (!/^\d+$/.test(width)) {
|
|
2929
|
+
columns = void 0;
|
|
2930
|
+
break;
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
columns.push(parseFloat(width));
|
|
2934
|
+
}
|
|
2935
|
+
if (columns) tableNode.setColWidths(columns);
|
|
2936
|
+
}
|
|
2937
|
+
return {
|
|
2938
|
+
after: (children) => $descendantsMatching(children, $isTableRowNode),
|
|
2939
|
+
node: tableNode
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2942
|
+
function $createTableNode() {
|
|
2943
|
+
return $applyNodeReplacement(new TableNode());
|
|
2944
|
+
}
|
|
2945
|
+
function $isTableNode(node) {
|
|
2946
|
+
return node instanceof TableNode;
|
|
2947
|
+
}
|
|
2948
|
+
function $insertTable({ rows, columns, includeHeaders }, hasNestedTables) {
|
|
2949
|
+
const selection = $getSelection() || $getPreviousSelection();
|
|
2950
|
+
if (!selection || !$isRangeSelection(selection)) return false;
|
|
2951
|
+
if (!hasNestedTables && $findTableNode(selection.anchor.getNode())) return false;
|
|
2952
|
+
const tableNode = $createTableNodeWithDimensions(Number(rows), Number(columns), includeHeaders);
|
|
2953
|
+
$insertNodeToNearestRoot(tableNode);
|
|
2954
|
+
const firstDescendant = tableNode.getFirstDescendant();
|
|
2955
|
+
if ($isTextNode(firstDescendant)) firstDescendant.select();
|
|
2956
|
+
return true;
|
|
2957
|
+
}
|
|
2958
|
+
function $tableCellTransform(node) {
|
|
2959
|
+
if (!$isTableRowNode(node.getParent())) node.remove();
|
|
2960
|
+
else if (node.isEmpty()) node.append($createParagraphNode());
|
|
2961
|
+
}
|
|
2962
|
+
function $tableRowTransform(node) {
|
|
2963
|
+
if (!$isTableNode(node.getParent())) node.remove();
|
|
2964
|
+
else $unwrapAndFilterDescendants(node, $isTableCellNode);
|
|
2965
|
+
}
|
|
2966
|
+
function $tableTransform(node) {
|
|
2967
|
+
$unwrapAndFilterDescendants(node, $isTableRowNode);
|
|
2968
|
+
const [gridMap] = $computeTableMapSkipCellCheck(node, null, null);
|
|
2969
|
+
const maxRowLength = gridMap.reduce((curLength, row) => {
|
|
2970
|
+
return Math.max(curLength, row.length);
|
|
2971
|
+
}, 0);
|
|
2972
|
+
const rowNodes = node.getChildren();
|
|
2973
|
+
for (let i = 0; i < gridMap.length; ++i) {
|
|
2974
|
+
const rowNode = rowNodes[i];
|
|
2975
|
+
if (!rowNode) continue;
|
|
2976
|
+
if (!$isTableRowNode(rowNode)) formatDevErrorMessage(`TablePlugin: Expecting all children of TableNode to be TableRowNode, found ${rowNode.constructor.name} (type ${rowNode.getType()})`);
|
|
2977
|
+
const rowLength = gridMap[i].reduce((acc, cell) => cell ? 1 + acc : acc, 0);
|
|
2978
|
+
if (rowLength === maxRowLength) continue;
|
|
2979
|
+
for (let j = rowLength; j < maxRowLength; ++j) {
|
|
2980
|
+
const newCell = $createTableCellNode();
|
|
2981
|
+
newCell.append($createParagraphNode());
|
|
2982
|
+
rowNode.append(newCell);
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
const colWidths = node.getColWidths();
|
|
2986
|
+
const columnCount = node.getColumnCount();
|
|
2987
|
+
if (colWidths && colWidths.length !== columnCount) {
|
|
2988
|
+
let newColWidths = void 0;
|
|
2989
|
+
if (columnCount < colWidths.length) newColWidths = colWidths.slice(0, columnCount);
|
|
2990
|
+
else if (colWidths.length > 0) {
|
|
2991
|
+
const fillWidth = colWidths[colWidths.length - 1];
|
|
2992
|
+
newColWidths = [...colWidths, ...Array(columnCount - colWidths.length).fill(fillWidth)];
|
|
2993
|
+
}
|
|
2994
|
+
node.setColWidths(newColWidths);
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
function $tableClickCommand(event) {
|
|
2998
|
+
if (event.detail < 3 || !isDOMNode(event.target)) return false;
|
|
2999
|
+
const startNode = $getNearestNodeFromDOMNode(event.target);
|
|
3000
|
+
if (startNode === null) return false;
|
|
3001
|
+
const blockNode = $findMatchingParent(startNode, (node) => $isElementNode(node) && !node.isInline());
|
|
3002
|
+
if (blockNode === null) return false;
|
|
3003
|
+
if (!$isTableCellNode(blockNode.getParent())) return false;
|
|
3004
|
+
blockNode.select(0);
|
|
3005
|
+
return true;
|
|
3006
|
+
}
|
|
3007
|
+
function $tableSelectAllCommand() {
|
|
3008
|
+
const selection = $getSelection();
|
|
3009
|
+
if (!$isRangeSelection(selection)) return false;
|
|
3010
|
+
const tableNode = $findTableNode(selection.anchor.getNode());
|
|
3011
|
+
if (tableNode === null) return false;
|
|
3012
|
+
const root = $getRoot();
|
|
3013
|
+
if (!root.is(tableNode.getParent()) || root.getChildrenSize() !== 1) return false;
|
|
3014
|
+
const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
|
|
3015
|
+
if (tableMap.length === 0 || tableMap[0].length === 0) return false;
|
|
3016
|
+
const firstCellMap = tableMap[0][0];
|
|
3017
|
+
if (!firstCellMap || !firstCellMap.cell) return false;
|
|
3018
|
+
const lastRow = tableMap[tableMap.length - 1];
|
|
3019
|
+
const lastCellMap = lastRow[lastRow.length - 1];
|
|
3020
|
+
if (!lastCellMap || !lastCellMap.cell) return false;
|
|
3021
|
+
$setSelection($createTableSelectionFrom(tableNode, firstCellMap.cell, lastCellMap.cell));
|
|
3022
|
+
return true;
|
|
3023
|
+
}
|
|
3024
|
+
/**
|
|
3025
|
+
* Register a transform to ensure that all TableCellNode have a colSpan and rowSpan of 1.
|
|
3026
|
+
* This should only be registered when you do not want to support merged cells.
|
|
3027
|
+
*
|
|
3028
|
+
* @param editor The editor
|
|
3029
|
+
* @returns An unregister callback
|
|
3030
|
+
*/
|
|
3031
|
+
function registerTableCellUnmergeTransform(editor) {
|
|
3032
|
+
return editor.registerNodeTransform(TableCellNode, (node) => {
|
|
3033
|
+
if (node.getColSpan() > 1 || node.getRowSpan() > 1) {
|
|
3034
|
+
const [, , gridNode] = $getNodeTriplet(node);
|
|
3035
|
+
const [gridMap] = $computeTableMap(gridNode, node, node);
|
|
3036
|
+
const rowsCount = gridMap.length;
|
|
3037
|
+
const columnsCount = gridMap[0].length;
|
|
3038
|
+
let row = gridNode.getFirstChild();
|
|
3039
|
+
if (!$isTableRowNode(row)) formatDevErrorMessage(`Expected TableNode first child to be a RowNode`);
|
|
3040
|
+
const unmerged = [];
|
|
3041
|
+
for (let i = 0; i < rowsCount; i++) {
|
|
3042
|
+
if (i !== 0) {
|
|
3043
|
+
row = row.getNextSibling();
|
|
3044
|
+
if (!$isTableRowNode(row)) formatDevErrorMessage(`Expected TableNode first child to be a RowNode`);
|
|
3045
|
+
}
|
|
3046
|
+
let lastRowCell = null;
|
|
3047
|
+
for (let j = 0; j < columnsCount; j++) {
|
|
3048
|
+
const cellMap = gridMap[i][j];
|
|
3049
|
+
const cell = cellMap.cell;
|
|
3050
|
+
if (cellMap.startRow === i && cellMap.startColumn === j) {
|
|
3051
|
+
lastRowCell = cell;
|
|
3052
|
+
unmerged.push(cell);
|
|
3053
|
+
} else if (cell.getColSpan() > 1 || cell.getRowSpan() > 1) {
|
|
3054
|
+
if (!$isTableCellNode(cell)) formatDevErrorMessage(`Expected TableNode cell to be a TableCellNode`);
|
|
3055
|
+
const newCell = $createTableCellNode(cell.__headerState);
|
|
3056
|
+
if (lastRowCell !== null) lastRowCell.insertAfter(newCell);
|
|
3057
|
+
else $insertFirst$1(row, newCell);
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
for (const cell of unmerged) {
|
|
3062
|
+
cell.setColSpan(1);
|
|
3063
|
+
cell.setRowSpan(1);
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
});
|
|
3067
|
+
}
|
|
3068
|
+
function registerTableSelectionObserver(editor, hasTabHandler = true) {
|
|
3069
|
+
const tableObservers = new TableObservers();
|
|
3070
|
+
const initializeTableNode = (tableNode, nodeKey, dom) => {
|
|
3071
|
+
const tableElement = getTableElement(tableNode, dom);
|
|
3072
|
+
const tableSelection = applyTableHandlers(tableNode, tableElement, editor, hasTabHandler, tableObservers);
|
|
3073
|
+
tableObservers.observers.set(nodeKey, [tableSelection, tableElement]);
|
|
3074
|
+
};
|
|
3075
|
+
return mergeRegister(registerTableWindowHandlers(editor, tableObservers), editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
|
|
3076
|
+
return $handleTableSelectionChangeCommand(tableObservers, editor);
|
|
3077
|
+
}, COMMAND_PRIORITY_HIGH), editor.registerMutationListener(TableNode, (nodeMutations) => {
|
|
3078
|
+
editor.getEditorState().read(() => {
|
|
3079
|
+
for (const [nodeKey, mutation] of nodeMutations) {
|
|
3080
|
+
const tableSelection = tableObservers.observers.get(nodeKey);
|
|
3081
|
+
if (mutation === "created" || mutation === "updated") {
|
|
3082
|
+
const { tableNode, tableElement } = $getTableAndElementByKey(nodeKey);
|
|
3083
|
+
if (tableSelection === void 0) initializeTableNode(tableNode, nodeKey, tableElement);
|
|
3084
|
+
else if (tableElement !== tableSelection[1]) {
|
|
3085
|
+
tableSelection[0].removeListeners();
|
|
3086
|
+
tableObservers.observers.delete(nodeKey);
|
|
3087
|
+
initializeTableNode(tableNode, nodeKey, tableElement);
|
|
3088
|
+
}
|
|
3089
|
+
} else if (mutation === "destroyed") {
|
|
3090
|
+
if (tableSelection !== void 0) {
|
|
3091
|
+
tableSelection[0].removeListeners();
|
|
3092
|
+
tableObservers.observers.delete(nodeKey);
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
}, { editor });
|
|
3097
|
+
}, { skipInitialization: false }), () => {
|
|
3098
|
+
for (const [, [tableSelection]] of tableObservers.observers) tableSelection.removeListeners();
|
|
3099
|
+
});
|
|
3100
|
+
}
|
|
3101
|
+
/**
|
|
3102
|
+
* Register table command listeners and the table integrity transforms. The
|
|
3103
|
+
* table selection observer should be registered separately after this with
|
|
3104
|
+
* {@link registerTableSelectionObserver}.
|
|
3105
|
+
*
|
|
3106
|
+
* @param editor The editor
|
|
3107
|
+
* @returns An unregister callback
|
|
3108
|
+
*/
|
|
3109
|
+
function registerTablePlugin(editor, options) {
|
|
3110
|
+
if (!editor.hasNodes([TableNode])) formatDevErrorMessage(`TablePlugin: TableNode is not registered on editor`);
|
|
3111
|
+
const { hasNestedTables = signal(false) } = options ?? {};
|
|
3112
|
+
return mergeRegister(editor.registerCommand(INSERT_TABLE_COMMAND, (payload) => {
|
|
3113
|
+
return $insertTable(payload, hasNestedTables.peek());
|
|
3114
|
+
}, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, (payload, dispatchEditor) => {
|
|
3115
|
+
if (editor !== dispatchEditor) return false;
|
|
3116
|
+
return $tableSelectionInsertClipboardNodesCommand(payload, hasNestedTables);
|
|
3117
|
+
}, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SELECT_ALL_COMMAND, $tableSelectAllCommand, COMMAND_PRIORITY_LOW), editor.registerCommand(CLICK_COMMAND, $tableClickCommand, COMMAND_PRIORITY_EDITOR), editor.registerNodeTransform(TableNode, $tableTransform), editor.registerNodeTransform(TableRowNode, $tableRowTransform), editor.registerNodeTransform(TableCellNode, $tableCellTransform));
|
|
3118
|
+
}
|
|
3119
|
+
function $tableSelectionInsertClipboardNodesCommand(selectionPayload, hasNestedTables) {
|
|
3120
|
+
const { nodes, selection } = selectionPayload;
|
|
3121
|
+
if (!nodes.some((n) => $isTableNode(n) || $dfs(n).some((d) => $isTableNode(d.node)))) return false;
|
|
3122
|
+
const isTableSelection = $isTableSelection(selection);
|
|
3123
|
+
const isRangeSelection = $isRangeSelection(selection);
|
|
3124
|
+
if (!(isRangeSelection && $findMatchingParent(selection.anchor.getNode(), (n) => $isTableCellNode(n)) !== null && $findMatchingParent(selection.focus.getNode(), (n) => $isTableCellNode(n)) !== null || isTableSelection)) return false;
|
|
3125
|
+
if (nodes.length === 1 && $isTableNode(nodes[0])) return $insertTableIntoGrid(nodes[0], selection);
|
|
3126
|
+
if (isRangeSelection && hasNestedTables.peek() && !$isMultiCellTableSelection(selection)) return false;
|
|
3127
|
+
return true;
|
|
3128
|
+
}
|
|
3129
|
+
function $insertTableIntoGrid(tableNode, selection) {
|
|
3130
|
+
const anchorAndFocus = selection.getStartEndPoints();
|
|
3131
|
+
const isTableSelection = $isTableSelection(selection);
|
|
3132
|
+
if (anchorAndFocus === null) return false;
|
|
3133
|
+
const [anchor, focus] = anchorAndFocus;
|
|
3134
|
+
const [anchorCellNode, anchorRowNode, gridNode] = $getNodeTriplet(anchor);
|
|
3135
|
+
const focusCellNode = $findMatchingParent(focus.getNode(), (n) => $isTableCellNode(n));
|
|
3136
|
+
if (!$isTableCellNode(anchorCellNode) || !$isTableCellNode(focusCellNode) || !$isTableRowNode(anchorRowNode) || !$isTableNode(gridNode)) return false;
|
|
3137
|
+
const [initialGridMap, anchorCellMap, focusCellMap] = $computeTableMap(gridNode, anchorCellNode, focusCellNode);
|
|
3138
|
+
const [templateGridMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
|
|
3139
|
+
const initialRowCount = initialGridMap.length;
|
|
3140
|
+
const initialColCount = initialRowCount > 0 ? initialGridMap[0].length : 0;
|
|
3141
|
+
let startRow = anchorCellMap.startRow;
|
|
3142
|
+
let startCol = anchorCellMap.startColumn;
|
|
3143
|
+
let affectedRowCount = templateGridMap.length;
|
|
3144
|
+
let affectedColCount = affectedRowCount > 0 ? templateGridMap[0].length : 0;
|
|
3145
|
+
if (isTableSelection) {
|
|
3146
|
+
const selectionBoundary = $computeTableCellRectBoundary(initialGridMap, anchorCellMap, focusCellMap);
|
|
3147
|
+
const selectionRowCount = selectionBoundary.maxRow - selectionBoundary.minRow + 1;
|
|
3148
|
+
const selectionColCount = selectionBoundary.maxColumn - selectionBoundary.minColumn + 1;
|
|
3149
|
+
startRow = selectionBoundary.minRow;
|
|
3150
|
+
startCol = selectionBoundary.minColumn;
|
|
3151
|
+
affectedRowCount = Math.min(affectedRowCount, selectionRowCount);
|
|
3152
|
+
affectedColCount = Math.min(affectedColCount, selectionColCount);
|
|
3153
|
+
}
|
|
3154
|
+
let didPerformMergeOperations = false;
|
|
3155
|
+
const lastRowForUnmerge = Math.min(initialRowCount, startRow + affectedRowCount) - 1;
|
|
3156
|
+
const lastColForUnmerge = Math.min(initialColCount, startCol + affectedColCount) - 1;
|
|
3157
|
+
const unmergedKeys = /* @__PURE__ */ new Set();
|
|
3158
|
+
for (let row = startRow; row <= lastRowForUnmerge; row++) for (let col = startCol; col <= lastColForUnmerge; col++) {
|
|
3159
|
+
const cellMap = initialGridMap[row][col];
|
|
3160
|
+
if (unmergedKeys.has(cellMap.cell.getKey())) continue;
|
|
3161
|
+
if (cellMap.cell.__rowSpan === 1 && cellMap.cell.__colSpan === 1) continue;
|
|
3162
|
+
$unmergeCellNode(cellMap.cell);
|
|
3163
|
+
unmergedKeys.add(cellMap.cell.getKey());
|
|
3164
|
+
didPerformMergeOperations = true;
|
|
3165
|
+
}
|
|
3166
|
+
let [interimGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null);
|
|
3167
|
+
const rowsToInsert = affectedRowCount - initialRowCount + startRow;
|
|
3168
|
+
for (let i = 0; i < rowsToInsert; i++) {
|
|
3169
|
+
const cellMap = interimGridMap[initialRowCount - 1][0];
|
|
3170
|
+
$insertTableRowAtNode(cellMap.cell);
|
|
3171
|
+
}
|
|
3172
|
+
const colsToInsert = affectedColCount - initialColCount + startCol;
|
|
3173
|
+
for (let i = 0; i < colsToInsert; i++) {
|
|
3174
|
+
const cellMap = interimGridMap[0][initialColCount - 1];
|
|
3175
|
+
$insertTableColumnAtNode(cellMap.cell, true, false);
|
|
3176
|
+
}
|
|
3177
|
+
[interimGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null);
|
|
3178
|
+
for (let row = startRow; row < startRow + affectedRowCount; row++) for (let col = startCol; col < startCol + affectedColCount; col++) {
|
|
3179
|
+
const templateRow = row - startRow;
|
|
3180
|
+
const templateCol = col - startCol;
|
|
3181
|
+
const templateCellMap = templateGridMap[templateRow][templateCol];
|
|
3182
|
+
if (templateCellMap.startRow !== templateRow || templateCellMap.startColumn !== templateCol) continue;
|
|
3183
|
+
const templateCell = templateCellMap.cell;
|
|
3184
|
+
if (templateCell.__rowSpan !== 1 || templateCell.__colSpan !== 1) {
|
|
3185
|
+
const cellsToMerge = [];
|
|
3186
|
+
const lastRowForMerge = Math.min(row + templateCell.__rowSpan, startRow + affectedRowCount) - 1;
|
|
3187
|
+
const lastColForMerge = Math.min(col + templateCell.__colSpan, startCol + affectedColCount) - 1;
|
|
3188
|
+
for (let r = row; r <= lastRowForMerge; r++) for (let c = col; c <= lastColForMerge; c++) {
|
|
3189
|
+
const cellMap = interimGridMap[r][c];
|
|
3190
|
+
cellsToMerge.push(cellMap.cell);
|
|
3191
|
+
}
|
|
3192
|
+
$mergeCells(cellsToMerge);
|
|
3193
|
+
didPerformMergeOperations = true;
|
|
3194
|
+
}
|
|
3195
|
+
const { cell } = interimGridMap[row][col];
|
|
3196
|
+
const backgroundColor = templateCell.getBackgroundColor();
|
|
3197
|
+
if (backgroundColor !== null && backgroundColor !== void 0) cell.setBackgroundColor(backgroundColor);
|
|
3198
|
+
const originalChildren = cell.getChildren();
|
|
3199
|
+
templateCell.getChildren().forEach((child) => {
|
|
3200
|
+
if ($isTextNode(child)) {
|
|
3201
|
+
$createParagraphNode().append(child);
|
|
3202
|
+
cell.append(child);
|
|
3203
|
+
} else cell.append(child);
|
|
3204
|
+
});
|
|
3205
|
+
originalChildren.forEach((n) => n.remove());
|
|
3206
|
+
}
|
|
3207
|
+
if (isTableSelection && didPerformMergeOperations) {
|
|
3208
|
+
const [finalGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null);
|
|
3209
|
+
finalGridMap[anchorCellMap.startRow][anchorCellMap.startColumn].cell.selectEnd();
|
|
3210
|
+
}
|
|
3211
|
+
return true;
|
|
3212
|
+
}
|
|
3213
|
+
function $isMultiCellTableSelection(selection) {
|
|
3214
|
+
if ($isTableSelection(selection) && !selection.focus.getNode().is(selection.anchor.getNode())) return true;
|
|
3215
|
+
if ($isRangeSelection(selection) && $isTableCellNode(selection.anchor.getNode()) && !selection.anchor.getNode().is(selection.focus.getNode())) return true;
|
|
3216
|
+
return false;
|
|
3217
|
+
}
|
|
3218
|
+
/**
|
|
3219
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3220
|
+
*
|
|
3221
|
+
* This source code is licensed under the MIT license found in the
|
|
3222
|
+
* LICENSE file in the root directory of this source tree.
|
|
3223
|
+
*
|
|
3224
|
+
*/
|
|
3225
|
+
/**
|
|
3226
|
+
* Configures {@link TableNode}, {@link TableRowNode}, {@link TableCellNode} and
|
|
3227
|
+
* registers table behaviors (see {@link TableConfig})
|
|
3228
|
+
*/
|
|
3229
|
+
const TableExtension = defineExtension({
|
|
3230
|
+
build(editor, config, state) {
|
|
3231
|
+
return namedSignals(config);
|
|
3232
|
+
},
|
|
3233
|
+
config: safeCast({
|
|
3234
|
+
hasCellBackgroundColor: true,
|
|
3235
|
+
hasCellMerge: true,
|
|
3236
|
+
hasHorizontalScroll: true,
|
|
3237
|
+
hasNestedTables: false,
|
|
3238
|
+
hasTabHandler: true
|
|
3239
|
+
}),
|
|
3240
|
+
name: "@lexical/table/Table",
|
|
3241
|
+
nodes: () => [
|
|
3242
|
+
TableNode,
|
|
3243
|
+
TableRowNode,
|
|
3244
|
+
TableCellNode
|
|
3245
|
+
],
|
|
3246
|
+
register(editor, config, state) {
|
|
3247
|
+
const stores = state.getOutput();
|
|
3248
|
+
return mergeRegister(effect(() => {
|
|
3249
|
+
const hasHorizontalScroll = stores.hasHorizontalScroll.value;
|
|
3250
|
+
if ($isScrollableTablesActive(editor) !== hasHorizontalScroll) {
|
|
3251
|
+
setScrollableTablesActive(editor, hasHorizontalScroll);
|
|
3252
|
+
editor.registerNodeTransform(TableNode, () => {})();
|
|
3253
|
+
}
|
|
3254
|
+
}), registerTablePlugin(editor, stores), effect(() => registerTableSelectionObserver(editor, stores.hasTabHandler.value)), effect(() => stores.hasCellMerge.value ? void 0 : registerTableCellUnmergeTransform(editor)), effect(() => stores.hasCellBackgroundColor.value ? void 0 : editor.registerNodeTransform(TableCellNode, (node) => {
|
|
3255
|
+
if (node.getBackgroundColor() !== null) node.setBackgroundColor(null);
|
|
3256
|
+
})));
|
|
3257
|
+
}
|
|
3258
|
+
});
|
|
3259
|
+
//#endregion
|
|
3260
|
+
export { $computeTableMap, $computeTableMapSkipCellCheck, $createTableCellNode, $createTableNode, $createTableNodeWithDimensions, $createTableRowNode, $createTableSelection, $createTableSelectionFrom, $deleteTableColumn, $deleteTableColumnAtSelection, $deleteTableColumn__EXPERIMENTAL, $deleteTableRowAtSelection, $deleteTableRow__EXPERIMENTAL, $findCellNode, $findTableNode, $getElementForTableNode, $getNodeTriplet, $getTableAndElementByKey, $getTableCellNodeFromLexicalNode, $getTableCellNodeRect, $getTableColumnIndexFromTableCellNode, $getTableNodeFromLexicalNodeOrThrow, $getTableRowIndexFromTableCellNode, $getTableRowNodeFromTableCellNodeOrThrow, $insertTableColumn, $insertTableColumnAtSelection, $insertTableColumn__EXPERIMENTAL, $insertTableRow, $insertTableRowAtSelection, $insertTableRow__EXPERIMENTAL, $isScrollableTablesActive, $isSimpleTable, $isTableCellNode, $isTableNode, $isTableRowNode, $isTableSelection, $mergeCells, $moveTableColumn, $removeTableRowAtIndex, $unmergeCell, INSERT_TABLE_COMMAND, TableCellHeaderStates, TableCellNode, TableExtension, TableNode, TableObserver, TableRowNode, applyTableHandlers, getDOMCellFromTarget, getTableElement, getTableObserverFromTableElement, registerTableCellUnmergeTransform, registerTablePlugin, registerTableSelectionObserver, setScrollableTablesActive };
|
|
3261
|
+
|
|
3262
|
+
//# sourceMappingURL=LexicalTable.dev-CQkLHXJx.mjs.map
|