@lobehub/editor 4.24.1 → 4.25.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/es/codemirror/style.js +42 -0
- package/es/editor-kernel/kernel.js +3 -0
- package/es/editor-kernel/react/useDecorators.js +2 -4
- package/es/headless/collapsible-plugin.js +74 -0
- package/es/headless/index.js +2 -0
- package/es/headless.d.ts +18 -0
- package/es/headless.js +2479 -71
- package/es/index.d.ts +26 -3
- package/es/index.js +17 -2
- package/es/locale/index.d.ts +14 -0
- package/es/locale/index.js +14 -0
- package/es/plugins/block/command/index.js +24 -0
- package/es/plugins/block/plugin/index.js +7 -5
- package/es/plugins/block/react/ReactBlockPlugin.js +43 -1
- package/es/plugins/block/react/core/menu-position.js +20 -0
- package/es/plugins/block/react/drag/drag-session.js +3 -2
- package/es/plugins/block/react/drag/drag-utils.js +13 -1
- package/es/plugins/codemirror-block/index.d.ts +2 -1
- package/es/plugins/codemirror-block/plugin/index.js +2 -0
- package/es/plugins/codemirror-block/react/CodemirrorNode.js +95 -5
- package/es/plugins/codemirror-block/react/useCodemirrorEditLock.js +33 -0
- package/es/plugins/codemirror-block/service/index.d.ts +40 -0
- package/es/plugins/codemirror-block/service/index.js +59 -0
- package/es/plugins/collapsible/command/index.d.ts +17 -0
- package/es/plugins/collapsible/command/index.js +72 -0
- package/es/plugins/collapsible/index.d.ts +7 -0
- package/es/plugins/collapsible/node/CollapsibleNode.d.ts +30 -0
- package/es/plugins/collapsible/node/CollapsibleNode.js +138 -0
- package/es/plugins/collapsible/plugin/index.d.ts +11 -0
- package/es/plugins/collapsible/plugin/index.js +535 -0
- package/es/plugins/collapsible/react/ReactCollapsiblePlugin.d.ts +6 -0
- package/es/plugins/collapsible/react/ReactCollapsiblePlugin.js +19 -0
- package/es/plugins/collapsible/react/index.d.ts +3 -0
- package/es/plugins/collapsible/react/style.js +67 -0
- package/es/plugins/collapsible/react/type.d.ts +6 -0
- package/es/plugins/common/plugin/index.js +3 -2
- package/es/plugins/common/plugin/progressive-select-all.js +81 -0
- package/es/plugins/common/plugin/register.js +73 -4
- package/es/plugins/link/command/index.js +26 -3
- package/es/plugins/link/conversion/index.js +237 -0
- package/es/plugins/link/index.d.ts +5 -3
- package/es/plugins/link/node/LinkBlockCardNode.d.ts +16 -0
- package/es/plugins/link/node/LinkBlockCardNode.js +66 -0
- package/es/plugins/link/node/LinkCardNode.d.ts +42 -0
- package/es/plugins/link/node/LinkCardNode.js +161 -0
- package/es/plugins/link/node/LinkIframeNode.d.ts +33 -0
- package/es/plugins/link/node/LinkIframeNode.js +131 -0
- package/es/plugins/link/node/LinkNode.d.ts +48 -2
- package/es/plugins/link/node/LinkNode.js +14 -6
- package/es/plugins/link/node/SchemaNode.d.ts +36 -0
- package/es/plugins/link/node/SchemaNode.js +149 -0
- package/es/plugins/link/normalization/index.d.ts +7 -0
- package/es/plugins/link/normalization/index.js +38 -0
- package/es/plugins/link/plugin/index.d.ts +26 -1
- package/es/plugins/link/plugin/index.js +124 -4
- package/es/plugins/link/react/ReactLinkPlugin.js +165 -7
- package/es/plugins/link/react/components/LinkCard.js +235 -0
- package/es/plugins/link/react/components/LinkEdit.js +93 -14
- package/es/plugins/link/react/components/LinkIframe.js +128 -0
- package/es/plugins/link/react/components/LinkToolbar.js +440 -111
- package/es/plugins/link/react/components/SchemaLink.js +49 -0
- package/es/plugins/link/react/index.d.ts +2 -2
- package/es/plugins/link/react/renderer-registry.d.ts +81 -0
- package/es/plugins/link/react/renderer-registry.js +80 -0
- package/es/plugins/link/react/style.js +63 -1
- package/es/plugins/link/react/type.d.ts +24 -1
- package/es/plugins/link/service/i-link-service.d.ts +156 -1
- package/es/plugins/link/service/i-link-service.js +258 -5
- package/es/plugins/list/plugin/index.js +9 -2
- package/es/plugins/litexml/command/diffCommand.js +94 -14
- package/es/plugins/litexml/command/index.js +187 -6
- package/es/plugins/litexml/diff-validation.js +237 -0
- package/es/plugins/litexml/node/DiffContentNode.js +67 -0
- package/es/plugins/litexml/node/DiffNode.d.ts +1 -1
- package/es/plugins/litexml/node/DiffNode.js +5 -2
- package/es/plugins/litexml/node/TableCellDiffNode.js +77 -0
- package/es/plugins/litexml/node/TableRowDiffNode.js +73 -0
- package/es/plugins/litexml/plugin/index.d.ts +2 -0
- package/es/plugins/litexml/plugin/index.js +62 -9
- package/es/plugins/litexml/react/DiffNodeToolbar/index.js +10 -12
- package/es/plugins/litexml/react/TableRowDiffToolbar.js +123 -0
- package/es/plugins/litexml/react/hooks/useHasDiffNode.js +5 -2
- package/es/plugins/litexml/react/index.js +6 -2
- package/es/plugins/litexml/react/style.js +18 -5
- package/es/plugins/litexml/table-cell-diff.js +153 -0
- package/es/plugins/litexml/table-row-diff.js +82 -0
- package/es/plugins/markdown/data-source/markdown/parse.js +25 -1
- package/es/plugins/markdown/plugin/index.js +5 -3
- package/es/plugins/slash/react/ReactSlashPlugin.js +22 -43
- package/es/plugins/slash/react/components/DefaultSlashMenu.js +76 -16
- package/es/plugins/slash/react/menu-utils.js +84 -0
- package/es/plugins/slash/service/i-slash-service.d.ts +3 -0
- package/es/plugins/table/plugin/index.js +4 -1
- package/es/plugins/table/plugin/single-cell-paste.js +79 -0
- package/es/plugins/table/react/TableController/hooks.js +7 -4
- package/es/plugins/table/react/hooks.js +2 -2
- package/es/plugins/table/react/index.js +2 -0
- package/es/plugins/table/react/style.js +15 -5
- package/es/plugins/table/react/useScrollFocusedTableCellIntoView.js +46 -0
- package/es/plugins/toc/index.d.ts +10 -0
- package/es/plugins/toc/plugin/index.d.ts +8 -0
- package/es/plugins/toc/plugin/index.js +56 -0
- package/es/plugins/toc/react/ReactTocPlugin.d.ts +6 -0
- package/es/plugins/toc/react/ReactTocPlugin.js +36 -0
- package/es/plugins/toc/react/getNearestScrollContainer.d.ts +6 -0
- package/es/plugins/toc/react/getNearestScrollContainer.js +18 -0
- package/es/plugins/toc/react/hooks/useActiveHeading.js +59 -0
- package/es/plugins/toc/react/hooks/useTocItems.js +50 -0
- package/es/plugins/toc/react/index.d.ts +5 -0
- package/es/plugins/toc/react/type.d.ts +30 -0
- package/es/plugins/toc/react/useToc.d.ts +5 -0
- package/es/plugins/toc/react/useToc.js +41 -0
- package/es/plugins/toc/service/i-toc-service.d.ts +39 -0
- package/es/plugins/toc/service/i-toc-service.js +125 -0
- package/es/plugins/toc/service/index.d.ts +3 -0
- package/es/plugins/toc/types.d.ts +23 -0
- package/es/plugins/toc/utils/index.d.ts +6 -0
- package/es/plugins/toc/utils/index.js +30 -0
- package/es/plugins/toolbar/react/index.js +26 -12
- package/es/plugins/toolbar/react/style.js +3 -2
- package/es/plugins/virtual-block/plugin/register.js +34 -12
- package/es/plugins/yjs/index.d.ts +6 -0
- package/es/plugins/yjs/plugin/index.d.ts +7 -0
- package/es/plugins/yjs/plugin/index.js +191 -0
- package/es/plugins/yjs/plugin/types.d.ts +16 -0
- package/es/plugins/yjs/plugin/utils/awareness.js +9 -0
- package/es/plugins/yjs/plugin/utils/editor-state.js +47 -0
- package/es/plugins/yjs/plugin/utils/history.js +31 -0
- package/es/plugins/yjs/plugin/utils/node-properties.js +39 -0
- package/es/plugins/yjs/plugin/utils/sync.js +24 -0
- package/es/plugins/yjs/react/codemirrorEditLockProvider.js +59 -0
- package/es/plugins/yjs/react/index.d.ts +23 -0
- package/es/plugins/yjs/react/index.js +200 -0
- package/es/plugins/yjs/service/index.d.ts +47 -0
- package/es/plugins/yjs/service/index.js +84 -0
- package/es/plugins/yjs/websocket-provider.d.ts +78 -0
- package/es/plugins/yjs/websocket-provider.js +263 -0
- package/es/renderer/LexicalRenderer.js +9 -2
- package/es/types/kernel.d.ts +4 -0
- package/es/utils/updatePosition.js +5 -2
- package/package.json +3 -1
- package/patches/@lexical__yjs@0.42.0.patch +42 -0
- package/scripts/postinstall-lexical-patch.cjs +62 -36
|
@@ -3,18 +3,271 @@ import EventEmitter from "eventemitter3";
|
|
|
3
3
|
//#region src/plugins/link/service/i-link-service.ts
|
|
4
4
|
init_utils();
|
|
5
5
|
const ILinkService = genServiceId("LinkService");
|
|
6
|
+
const DEFAULT_LABELS = {
|
|
7
|
+
convertToBlockCard: "Convert to block card",
|
|
8
|
+
convertToCard: "Convert to card",
|
|
9
|
+
convertToIframe: "Convert to iframe",
|
|
10
|
+
convertToLink: "Convert to link",
|
|
11
|
+
convertToSchema: "Convert to schema"
|
|
12
|
+
};
|
|
13
|
+
var LinkProtocolPolicy = class {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.allowedProtocols = /* @__PURE__ */ new Set([
|
|
16
|
+
"http:",
|
|
17
|
+
"https:",
|
|
18
|
+
"mailto:",
|
|
19
|
+
"sms:",
|
|
20
|
+
"tel:"
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
getAllowedProtocols() {
|
|
24
|
+
return this.allowedProtocols;
|
|
25
|
+
}
|
|
26
|
+
setAllowedProtocols(protocols) {
|
|
27
|
+
this.allowedProtocols = new Set(protocols.map(normalizeProtocol));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var LinkRuleRegistry = class {
|
|
31
|
+
constructor() {
|
|
32
|
+
this.embedRules = [];
|
|
33
|
+
this.schemaRules = [];
|
|
34
|
+
}
|
|
35
|
+
getEmbedRule(url, context) {
|
|
36
|
+
return this.embedRules.find((rule) => rule.match(url, context)) || null;
|
|
37
|
+
}
|
|
38
|
+
getSchemaRule(url, context, parseSchemaUrl) {
|
|
39
|
+
const schema = context.schema === void 0 ? parseSchemaUrl(url) : context.schema;
|
|
40
|
+
return this.schemaRules.find((rule) => rule.match(url, {
|
|
41
|
+
...context,
|
|
42
|
+
schema
|
|
43
|
+
})) || null;
|
|
44
|
+
}
|
|
45
|
+
getSchemaRuleById(schemaType) {
|
|
46
|
+
return this.schemaRules.find((rule) => rule.id === schemaType) || null;
|
|
47
|
+
}
|
|
48
|
+
setEmbedRules(rules = []) {
|
|
49
|
+
this.embedRules = rules;
|
|
50
|
+
}
|
|
51
|
+
setSchemaRules(rules = []) {
|
|
52
|
+
this.schemaRules = rules;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var LegacySchemaLinkRegistry = class {
|
|
56
|
+
constructor() {
|
|
57
|
+
this.protocols = /* @__PURE__ */ new Set();
|
|
58
|
+
}
|
|
59
|
+
hasSchemaLinkRenderer(url) {
|
|
60
|
+
try {
|
|
61
|
+
const { protocol } = new URL(url);
|
|
62
|
+
return this.protocols.has(protocol);
|
|
63
|
+
} catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
setSchemaLinkRenderers(renderers = []) {
|
|
68
|
+
this.protocols = new Set(renderers.map(({ protocol }) => normalizeProtocol(protocol)));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var LinkToolbarController = class {
|
|
72
|
+
constructor() {
|
|
73
|
+
this.baseEnabled = true;
|
|
74
|
+
this.labels = DEFAULT_LABELS;
|
|
75
|
+
this.toolbarActions = [];
|
|
76
|
+
this.toolbarSuppressions = /* @__PURE__ */ new Set();
|
|
77
|
+
}
|
|
78
|
+
get enabled() {
|
|
79
|
+
return this.baseEnabled && this.toolbarSuppressions.size === 0;
|
|
80
|
+
}
|
|
81
|
+
getLabels() {
|
|
82
|
+
return this.labels;
|
|
83
|
+
}
|
|
84
|
+
getToolbarActions(context) {
|
|
85
|
+
return this.toolbarActions.filter((action) => action.visible?.(context) ?? true);
|
|
86
|
+
}
|
|
87
|
+
setLabels(labels) {
|
|
88
|
+
this.labels = {
|
|
89
|
+
...DEFAULT_LABELS,
|
|
90
|
+
...labels
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
setToolbarActions(actions = []) {
|
|
94
|
+
this.toolbarActions = actions;
|
|
95
|
+
}
|
|
96
|
+
setEnabled(enable) {
|
|
97
|
+
const previousEnabled = this.enabled;
|
|
98
|
+
this.baseEnabled = enable;
|
|
99
|
+
return previousEnabled !== this.enabled;
|
|
100
|
+
}
|
|
101
|
+
suppress(reason = "unknown") {
|
|
102
|
+
const previousEnabled = this.enabled;
|
|
103
|
+
const token = Symbol(reason);
|
|
104
|
+
this.toolbarSuppressions.add(token);
|
|
105
|
+
return {
|
|
106
|
+
changed: previousEnabled !== this.enabled,
|
|
107
|
+
token
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
restore(token) {
|
|
111
|
+
const previousEnabled = this.enabled;
|
|
112
|
+
if (!this.toolbarSuppressions.delete(token)) return false;
|
|
113
|
+
return previousEnabled !== this.enabled;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
6
116
|
var LinkService = class extends EventEmitter {
|
|
7
117
|
constructor(..._args) {
|
|
8
118
|
super(..._args);
|
|
9
|
-
this.
|
|
119
|
+
this.cardMetadataLoadingKeys = /* @__PURE__ */ new Set();
|
|
120
|
+
this.protocolPolicy = new LinkProtocolPolicy();
|
|
121
|
+
this.legacySchemaLinkRegistry = new LegacySchemaLinkRegistry();
|
|
122
|
+
this.ruleRegistry = new LinkRuleRegistry();
|
|
123
|
+
this.toolbarController = new LinkToolbarController();
|
|
124
|
+
this.toolbarItems = /* @__PURE__ */ new Map();
|
|
10
125
|
}
|
|
11
126
|
get enableLinkToolbar() {
|
|
12
|
-
return this.
|
|
127
|
+
return this.toolbarController.enabled;
|
|
128
|
+
}
|
|
129
|
+
getAllowedProtocols() {
|
|
130
|
+
return this.protocolPolicy.getAllowedProtocols();
|
|
131
|
+
}
|
|
132
|
+
getEmbedRule(url, context) {
|
|
133
|
+
return this.ruleRegistry.getEmbedRule(url, context);
|
|
134
|
+
}
|
|
135
|
+
getLabels() {
|
|
136
|
+
return this.toolbarController.getLabels();
|
|
137
|
+
}
|
|
138
|
+
hasSchemaLinkRenderer(url) {
|
|
139
|
+
return this.legacySchemaLinkRegistry.hasSchemaLinkRenderer(url);
|
|
140
|
+
}
|
|
141
|
+
isCardMetadataLoading(nodeKey) {
|
|
142
|
+
return this.cardMetadataLoadingKeys.has(nodeKey);
|
|
143
|
+
}
|
|
144
|
+
setCardMetadataLoading(nodeKey, loading) {
|
|
145
|
+
if (!(loading ? !this.cardMetadataLoadingKeys.has(nodeKey) : this.cardMetadataLoadingKeys.has(nodeKey))) return;
|
|
146
|
+
if (loading) this.cardMetadataLoadingKeys.add(nodeKey);
|
|
147
|
+
else this.cardMetadataLoadingKeys.delete(nodeKey);
|
|
148
|
+
this.emit("cardMetadataChange");
|
|
149
|
+
}
|
|
150
|
+
getSchemaRule(url, context) {
|
|
151
|
+
return this.ruleRegistry.getSchemaRule(url, context, (url) => this.parseSchemaUrl(url));
|
|
152
|
+
}
|
|
153
|
+
getToolbarActions(context) {
|
|
154
|
+
return this.toolbarController.getToolbarActions(context);
|
|
155
|
+
}
|
|
156
|
+
parseSchemaUrl(url) {
|
|
157
|
+
try {
|
|
158
|
+
const parsedUrl = new URL(url);
|
|
159
|
+
return {
|
|
160
|
+
hash: parsedUrl.hash,
|
|
161
|
+
host: parsedUrl.host,
|
|
162
|
+
params: Object.fromEntries(parsedUrl.searchParams.entries()),
|
|
163
|
+
pathname: parsedUrl.pathname,
|
|
164
|
+
protocol: parsedUrl.protocol,
|
|
165
|
+
raw: url,
|
|
166
|
+
search: parsedUrl.search
|
|
167
|
+
};
|
|
168
|
+
} catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
updateConfig(config) {
|
|
173
|
+
this.setAllowedProtocols([
|
|
174
|
+
"http:",
|
|
175
|
+
"https:",
|
|
176
|
+
"mailto:",
|
|
177
|
+
"sms:",
|
|
178
|
+
"tel:",
|
|
179
|
+
...config?.schemaLinkRenderers?.map(({ protocol }) => protocol) || [],
|
|
180
|
+
...config?.allowedProtocols || []
|
|
181
|
+
]);
|
|
182
|
+
this.setEmbedRules(config?.linkEmbedRules);
|
|
183
|
+
this.setLabels(config?.labels);
|
|
184
|
+
this.setSchemaLinkRenderers(config?.schemaLinkRenderers);
|
|
185
|
+
this.setSchemaRules([...config?.schemaRules || [], ...createLegacySchemaRules(config?.schemaLinkRenderers)]);
|
|
186
|
+
this.setToolbarActions(config?.toolbarActions);
|
|
187
|
+
}
|
|
188
|
+
setAllowedProtocols(protocols) {
|
|
189
|
+
this.protocolPolicy.setAllowedProtocols(protocols);
|
|
190
|
+
}
|
|
191
|
+
setEmbedRules(rules = []) {
|
|
192
|
+
this.ruleRegistry.setEmbedRules(rules);
|
|
193
|
+
}
|
|
194
|
+
setLabels(labels) {
|
|
195
|
+
this.toolbarController.setLabels(labels);
|
|
196
|
+
}
|
|
197
|
+
setSchemaLinkRenderers(renderers = []) {
|
|
198
|
+
this.legacySchemaLinkRegistry.setSchemaLinkRenderers(renderers);
|
|
199
|
+
}
|
|
200
|
+
setSchemaRules(rules = []) {
|
|
201
|
+
this.ruleRegistry.setSchemaRules(rules);
|
|
202
|
+
}
|
|
203
|
+
setToolbarActions(actions = []) {
|
|
204
|
+
this.toolbarController.setToolbarActions(actions);
|
|
205
|
+
this.emit("change");
|
|
206
|
+
}
|
|
207
|
+
getToolbarItems(context) {
|
|
208
|
+
return Array.from(this.toolbarItems.values()).filter((item) => item.when ? item.when(context) : true).sort((a, b) => (a.order || 0) - (b.order || 0));
|
|
209
|
+
}
|
|
210
|
+
registerToolbarItem(item) {
|
|
211
|
+
this.toolbarItems.set(item.key, item);
|
|
212
|
+
this.emit("change");
|
|
213
|
+
return () => {
|
|
214
|
+
this.toolbarItems.delete(item.key);
|
|
215
|
+
this.emit("change");
|
|
216
|
+
};
|
|
13
217
|
}
|
|
14
218
|
setLinkToolbar(enable) {
|
|
15
|
-
this.
|
|
16
|
-
|
|
219
|
+
if (this.toolbarController.setEnabled(enable)) this.emit("linkToolbarChange", enable);
|
|
220
|
+
}
|
|
221
|
+
suppressLinkToolbar(reason = "unknown") {
|
|
222
|
+
const { changed, token } = this.toolbarController.suppress(reason);
|
|
223
|
+
if (changed) this.emit("linkToolbarChange", this.toolbarController.enabled);
|
|
224
|
+
return token;
|
|
225
|
+
}
|
|
226
|
+
restoreLinkToolbar(token) {
|
|
227
|
+
if (this.toolbarController.restore(token)) this.emit("linkToolbarChange", this.toolbarController.enabled);
|
|
228
|
+
}
|
|
229
|
+
subscribe(listener) {
|
|
230
|
+
this.on("change", listener);
|
|
231
|
+
return () => {
|
|
232
|
+
this.off("change", listener);
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
subscribeCardMetadata(listener) {
|
|
236
|
+
this.on("cardMetadataChange", listener);
|
|
237
|
+
return () => {
|
|
238
|
+
this.off("cardMetadataChange", listener);
|
|
239
|
+
};
|
|
17
240
|
}
|
|
18
241
|
};
|
|
242
|
+
function normalizeProtocol(protocol) {
|
|
243
|
+
return `${protocol.split(":")[0]}:`;
|
|
244
|
+
}
|
|
245
|
+
function createLegacySchemaRules(renderers = []) {
|
|
246
|
+
return renderers.map(({ protocol }) => {
|
|
247
|
+
const normalizedProtocol = normalizeProtocol(protocol);
|
|
248
|
+
return {
|
|
249
|
+
id: normalizedProtocol.replace(":", ""),
|
|
250
|
+
match: (url) => {
|
|
251
|
+
try {
|
|
252
|
+
return new URL(url).protocol === normalizedProtocol;
|
|
253
|
+
} catch {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
function getNodeUrl(node) {
|
|
261
|
+
const maybeUrlNode = node;
|
|
262
|
+
if (typeof maybeUrlNode.getURL === "function") return maybeUrlNode.getURL();
|
|
263
|
+
return "";
|
|
264
|
+
}
|
|
265
|
+
function getNodeTitle(node) {
|
|
266
|
+
const maybeTitleNode = node;
|
|
267
|
+
if (typeof maybeTitleNode.getTitle === "function") return maybeTitleNode.getTitle() || getNodeUrl(node);
|
|
268
|
+
const maybeTextNode = node;
|
|
269
|
+
if (typeof maybeTextNode.getTextContent === "function") return maybeTextNode.getTextContent() || getNodeUrl(node);
|
|
270
|
+
return getNodeUrl(node);
|
|
271
|
+
}
|
|
19
272
|
//#endregion
|
|
20
|
-
export { ILinkService, LinkService };
|
|
273
|
+
export { ILinkService, LinkService, createLegacySchemaRules, getNodeTitle, getNodeUrl, normalizeProtocol };
|
|
@@ -119,7 +119,11 @@ const ListPlugin = class extends KernelPlugin {
|
|
|
119
119
|
type: "element"
|
|
120
120
|
});
|
|
121
121
|
markdownService.registerMarkdownWriter(ListNode.getType(), (ctx, node) => {
|
|
122
|
-
if ($isListNode(node))
|
|
122
|
+
if ($isListNode(node)) {
|
|
123
|
+
const parent = node.getParent();
|
|
124
|
+
const needsLeadingNewline = $isListItemNode(parent) && node.getPreviousSibling() !== null;
|
|
125
|
+
ctx.wrap(needsLeadingNewline ? "\n" : "", "\n");
|
|
126
|
+
}
|
|
123
127
|
});
|
|
124
128
|
const getLevel = (node) => {
|
|
125
129
|
if (!node) return 0;
|
|
@@ -150,7 +154,10 @@ const ListPlugin = class extends KernelPlugin {
|
|
|
150
154
|
let start = node.start || 1;
|
|
151
155
|
return INodeHelper.createElementNode("list", {
|
|
152
156
|
children: children.map((v) => {
|
|
153
|
-
if (v.type === "listitem")
|
|
157
|
+
if (v.type === "listitem") {
|
|
158
|
+
v.value = start;
|
|
159
|
+
if (v.children?.[0]?.type !== "list") start++;
|
|
160
|
+
}
|
|
154
161
|
return v;
|
|
155
162
|
}),
|
|
156
163
|
direction: "ltr",
|
|
@@ -1,13 +1,76 @@
|
|
|
1
|
+
import { $isDiffContentNode } from "../node/DiffContentNode.js";
|
|
1
2
|
import { DiffNode } from "../node/DiffNode.js";
|
|
3
|
+
import { $isTableCellDiffNode } from "../node/TableCellDiffNode.js";
|
|
4
|
+
import { $createPlainTableCellFromDiff, $getTableCellColumnIndex, $getTableCellDiffGroup, $getTableForCell, $removeTableWidthsForCompleteCellGroup, $shrinkTableWidthsAfterCellRemoval } from "../table-cell-diff.js";
|
|
5
|
+
import { $isTableRowDiffNode } from "../node/TableRowDiffNode.js";
|
|
6
|
+
import { $createPlainTableRowFromDiff, $getTableRowDiffPair } from "../table-row-diff.js";
|
|
2
7
|
import { DiffAction, LITEXML_DIFFNODE_ALL_COMMAND, LITEXML_DIFFNODE_COMMAND } from "./symbols.js";
|
|
3
8
|
import { $getNodeByKey, $isElementNode, COMMAND_PRIORITY_EDITOR } from "lexical";
|
|
4
9
|
import { mergeRegister } from "@lexical/utils";
|
|
5
10
|
//#region src/plugins/litexml/command/diffCommand.ts
|
|
6
|
-
function
|
|
11
|
+
function doTableRowAction(editor, node, action) {
|
|
12
|
+
const pair = $getTableRowDiffPair(node);
|
|
13
|
+
if (pair) {
|
|
14
|
+
const survivingRow = action === 1 ? pair.add : pair.remove;
|
|
15
|
+
const discardedRow = action === 1 ? pair.remove : pair.add;
|
|
16
|
+
const plainRow = $createPlainTableRowFromDiff(editor, survivingRow);
|
|
17
|
+
discardedRow.remove();
|
|
18
|
+
survivingRow.replace(plainRow, false);
|
|
19
|
+
plainRow.selectStart();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (node.getDiffType() === "remove") {
|
|
23
|
+
if (action === 1) node.remove();
|
|
24
|
+
else {
|
|
25
|
+
const plainRow = $createPlainTableRowFromDiff(editor, node);
|
|
26
|
+
node.replace(plainRow, false);
|
|
27
|
+
plainRow.selectStart();
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (action === 1) {
|
|
32
|
+
const plainRow = $createPlainTableRowFromDiff(editor, node);
|
|
33
|
+
node.replace(plainRow, false);
|
|
34
|
+
plainRow.selectStart();
|
|
35
|
+
} else node.remove();
|
|
36
|
+
}
|
|
37
|
+
function doTableCellAction(editor, node, action) {
|
|
38
|
+
const group = $getTableCellDiffGroup(node);
|
|
39
|
+
const table = $getTableForCell(node);
|
|
40
|
+
const columnIndex = $getTableCellColumnIndex(node);
|
|
41
|
+
const span = node.getColSpan();
|
|
42
|
+
if (node.getDiffType() === "add" && action === 1 || node.getDiffType() === "remove" && action === 0) {
|
|
43
|
+
group.forEach((cell) => cell.replace($createPlainTableCellFromDiff(editor, cell), false));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (table && columnIndex >= 0) {
|
|
47
|
+
const widthCount = table.getColWidths()?.length;
|
|
48
|
+
$removeTableWidthsForCompleteCellGroup(table, group, columnIndex, span);
|
|
49
|
+
group.forEach((cell) => cell.remove());
|
|
50
|
+
if (table.getColWidths()?.length === widthCount) $shrinkTableWidthsAfterCellRemoval(table, columnIndex, span);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
group.forEach((cell) => cell.remove());
|
|
54
|
+
}
|
|
55
|
+
function doAction(editor, node, action) {
|
|
56
|
+
if ($isTableRowDiffNode(node)) {
|
|
57
|
+
doTableRowAction(editor, node, action);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const parent = node.getParent();
|
|
61
|
+
if ($isTableCellDiffNode(parent)) {
|
|
62
|
+
doTableCellAction(editor, parent, action);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
7
65
|
if (node.diffType === "modify") {
|
|
8
66
|
const children = node.getChildren();
|
|
9
|
-
|
|
10
|
-
|
|
67
|
+
const selectedChild = action === 1 ? children[1] : children[0];
|
|
68
|
+
if ($isDiffContentNode(selectedChild)) {
|
|
69
|
+
const parent = node.getParentOrThrow();
|
|
70
|
+
selectedChild.getChildren().forEach((child) => node.insertBefore(child));
|
|
71
|
+
node.remove();
|
|
72
|
+
if ($isElementNode(parent)) parent.selectEnd();
|
|
73
|
+
} else if (selectedChild) node.replace(selectedChild, false).selectEnd();
|
|
11
74
|
}
|
|
12
75
|
if (node.diffType === "remove") {
|
|
13
76
|
if (action === 1) node.remove();
|
|
@@ -19,7 +82,10 @@ function doAction(node, action) {
|
|
|
19
82
|
if (node.diffType === "add") {
|
|
20
83
|
if (action === 1) {
|
|
21
84
|
const children = node.getChildren();
|
|
22
|
-
node.
|
|
85
|
+
const parent = node.getParentOrThrow();
|
|
86
|
+
children.forEach((child) => node.insertBefore(child));
|
|
87
|
+
node.remove();
|
|
88
|
+
if ($isElementNode(parent)) parent.selectEnd();
|
|
23
89
|
} else if (action === 0) node.remove();
|
|
24
90
|
}
|
|
25
91
|
if (node.diffType === "listItemModify") {
|
|
@@ -65,23 +131,37 @@ function doAction(node, action) {
|
|
|
65
131
|
function registerLiteXMLDiffCommand(editor) {
|
|
66
132
|
return mergeRegister(editor.registerCommand(LITEXML_DIFFNODE_COMMAND, (payload) => {
|
|
67
133
|
const { action, nodeKey } = payload;
|
|
68
|
-
const node = editor.getEditorState().read(() => {
|
|
69
|
-
return $getNodeByKey(nodeKey);
|
|
70
|
-
});
|
|
71
|
-
if (!node) return false;
|
|
72
134
|
editor.update(() => {
|
|
73
|
-
|
|
135
|
+
const node = $getNodeByKey(nodeKey);
|
|
136
|
+
if (!(node instanceof DiffNode) && !$isTableRowDiffNode(node)) return;
|
|
137
|
+
doAction(editor, node, action);
|
|
74
138
|
});
|
|
75
139
|
return false;
|
|
76
140
|
}, COMMAND_PRIORITY_EDITOR), editor.registerCommand(LITEXML_DIFFNODE_ALL_COMMAND, (payload) => {
|
|
77
141
|
const { action } = payload;
|
|
78
|
-
const
|
|
79
|
-
return Array.from(editor._editorState._nodeMap.values()).filter((
|
|
142
|
+
const nodeKeys = editor.getEditorState().read(() => {
|
|
143
|
+
return Array.from(editor._editorState._nodeMap.values()).filter((node) => (node instanceof DiffNode || $isTableRowDiffNode(node)) && !!node.getParent()).map((node) => node.getKey());
|
|
80
144
|
});
|
|
81
|
-
if (!
|
|
145
|
+
if (!nodeKeys.length) return false;
|
|
82
146
|
editor.update(() => {
|
|
83
|
-
|
|
84
|
-
|
|
147
|
+
const handled = /* @__PURE__ */ new Set();
|
|
148
|
+
nodeKeys.forEach((nodeKey) => {
|
|
149
|
+
if (handled.has(nodeKey)) return;
|
|
150
|
+
const node = $getNodeByKey(nodeKey);
|
|
151
|
+
if (!(node instanceof DiffNode) && !$isTableRowDiffNode(node)) return;
|
|
152
|
+
const pair = $isTableRowDiffNode(node) ? $getTableRowDiffPair(node) : null;
|
|
153
|
+
if (pair) {
|
|
154
|
+
handled.add(pair.remove.getKey());
|
|
155
|
+
handled.add(pair.add.getKey());
|
|
156
|
+
} else {
|
|
157
|
+
const parent = node instanceof DiffNode ? node.getParent() : null;
|
|
158
|
+
if ($isTableCellDiffNode(parent)) $getTableCellDiffGroup(parent).forEach((cell) => {
|
|
159
|
+
const diff = cell.getFirstChild();
|
|
160
|
+
if (diff instanceof DiffNode) handled.add(diff.getKey());
|
|
161
|
+
});
|
|
162
|
+
handled.add(nodeKey);
|
|
163
|
+
}
|
|
164
|
+
doAction(editor, node, action);
|
|
85
165
|
});
|
|
86
166
|
});
|
|
87
167
|
return false;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { createDebugLogger, init_debug } from "../../../utils/debug.js";
|
|
2
|
-
import { $closest, init_utils } from "../../../editor-kernel/utils.js";
|
|
3
|
-
import {
|
|
2
|
+
import { $closest, getKernelFromEditor, init_utils } from "../../../editor-kernel/utils.js";
|
|
3
|
+
import { findNewIllegalDiffPaths, projectLiteXmlOperation } from "../diff-validation.js";
|
|
4
|
+
import { $createDiffContentNode, $isDiffContentNode } from "../node/DiffContentNode.js";
|
|
5
|
+
import { $createDiffNode, $isDiffNode, DiffNode } from "../node/DiffNode.js";
|
|
6
|
+
import { $isTableCellDiffNode } from "../node/TableCellDiffNode.js";
|
|
4
7
|
import { $cloneNode, $parseSerializedNodeImpl, charToId } from "../utils/index.js";
|
|
8
|
+
import { $createTableCellDiffFromCell, $getLogicalRowWidth, $getTableCellColumnIndex, $getTableForCell, $shrinkTableWidthsAfterCellRemoval, $updateTableWidthsForCellInsertion } from "../table-cell-diff.js";
|
|
9
|
+
import { $areTableRowStructuresCompatible, $createTableRowDiffFromRow } from "../table-row-diff.js";
|
|
5
10
|
import { LITEXML_APPLY_COMMAND, LITEXML_INSERT_COMMAND, LITEXML_MODIFY_COMMAND, LITEXML_REMOVE_COMMAND } from "./symbols.js";
|
|
11
|
+
import { $isTableCellNode, $isTableNode, $isTableRowNode } from "@lexical/table";
|
|
6
12
|
import { $createParagraphNode, $getNodeByKey, $getRoot, $insertNodes, $isElementNode, COMMAND_PRIORITY_EDITOR } from "lexical";
|
|
7
13
|
import { mergeRegister } from "@lexical/utils";
|
|
8
14
|
import { $isListItemNode } from "@lexical/list";
|
|
@@ -13,6 +19,34 @@ const logger = createDebugLogger("plugin", "litexml");
|
|
|
13
19
|
function toArrayXml(litexml) {
|
|
14
20
|
return Array.isArray(litexml) ? litexml : [litexml];
|
|
15
21
|
}
|
|
22
|
+
function hasNewIllegalDiffs(previous, projected) {
|
|
23
|
+
return findNewIllegalDiffPaths(previous, projected);
|
|
24
|
+
}
|
|
25
|
+
function projectOperation(dataSource, document, operation) {
|
|
26
|
+
try {
|
|
27
|
+
const projected = projectLiteXmlOperation(document, operation, (xml) => dataSource.readLiteXMLToInode(xml));
|
|
28
|
+
const newIllegalDiffs = hasNewIllegalDiffs(document, projected);
|
|
29
|
+
if (newIllegalDiffs.length > 0) {
|
|
30
|
+
logger.warn("⚠️ Skipping operation with illegal nested diff", newIllegalDiffs);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return projected;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
logger.error("❌ Failed to preflight LiteXML operation:", error);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function toProjectionOperation(operation) {
|
|
40
|
+
if (operation.action === "remove") return {
|
|
41
|
+
...operation,
|
|
42
|
+
id: charToId(operation.id)
|
|
43
|
+
};
|
|
44
|
+
if (operation.action === "insert") return {
|
|
45
|
+
...operation,
|
|
46
|
+
..."beforeId" in operation ? { beforeId: operation.beforeId === "root" ? "root" : charToId(operation.beforeId) } : { afterId: operation.afterId === "root" ? "root" : charToId(operation.afterId) }
|
|
47
|
+
};
|
|
48
|
+
return operation;
|
|
49
|
+
}
|
|
16
50
|
function tryParseChild(child, editor) {
|
|
17
51
|
try {
|
|
18
52
|
const oldNode = $getNodeByKey(child.id);
|
|
@@ -29,6 +63,47 @@ function tryParseChild(child, editor) {
|
|
|
29
63
|
}
|
|
30
64
|
}
|
|
31
65
|
function handleReplaceForApplyDelay(oldNode, newNode, modifyBlockNodes, diffNodeMap, editor) {
|
|
66
|
+
if ($isTableRowNode(oldNode) || $isTableRowNode(newNode)) {
|
|
67
|
+
if (!$isTableRowNode(oldNode) || !$isTableRowNode(newNode) || !$isTableNode(oldNode.getParent()) || !$areTableRowStructuresCompatible(oldNode, newNode)) {
|
|
68
|
+
logger.error(`❌ Invalid table row modification for row ${oldNode.getKey()}.`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const changeId = `${oldNode.getKey()}:${newNode.getKey()}`;
|
|
72
|
+
const removeRow = $createTableRowDiffFromRow(editor, oldNode, "remove", changeId);
|
|
73
|
+
const addRow = $createTableRowDiffFromRow(editor, newNode, "add", changeId);
|
|
74
|
+
oldNode.replace(removeRow, false);
|
|
75
|
+
removeRow.insertAfter(addRow);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if ($isTableCellNode(oldNode) && $isTableCellNode(newNode)) {
|
|
79
|
+
const existingDiff = oldNode.getChildren().find($isDiffNode);
|
|
80
|
+
if (existingDiff) {
|
|
81
|
+
if ($isTableCellDiffNode(oldNode)) {
|
|
82
|
+
existingDiff.clear();
|
|
83
|
+
newNode.getChildren().forEach((child) => {
|
|
84
|
+
existingDiff.append($cloneNode(child, editor));
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const after = existingDiff.getChildren().find((child) => $isDiffContentNode(child) && child.side === "after");
|
|
89
|
+
if (existingDiff.diffType === "modify" && after && $isDiffContentNode(after)) {
|
|
90
|
+
after.clear();
|
|
91
|
+
newNode.getChildren().forEach((child) => {
|
|
92
|
+
after.append($cloneNode(child, editor));
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const before = $createDiffContentNode("before");
|
|
98
|
+
const after = $createDiffContentNode("after");
|
|
99
|
+
oldNode.getChildren().forEach((child) => before.append($cloneNode(child, editor)));
|
|
100
|
+
newNode.getChildren().forEach((child) => after.append($cloneNode(child, editor)));
|
|
101
|
+
const diffNode = $createDiffNode("modify");
|
|
102
|
+
diffNode.append(before, after);
|
|
103
|
+
oldNode.clear();
|
|
104
|
+
oldNode.append(diffNode);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
32
107
|
const oldBlock = $closest(oldNode, (node) => node.isInline() === false);
|
|
33
108
|
if (!oldBlock) throw new Error("Old block node not found for diffing.");
|
|
34
109
|
if ($closest(oldNode, (node) => node.getType() === DiffNode.getType())) {
|
|
@@ -112,8 +187,15 @@ function registerLiteXMLCommand(editor, dataSource) {
|
|
|
112
187
|
else acc.push(cur);
|
|
113
188
|
return acc;
|
|
114
189
|
}, []);
|
|
190
|
+
let projectedDocument = getKernelFromEditor(editor).getDocument("json");
|
|
191
|
+
const safePayload = resultPayload.filter((item) => {
|
|
192
|
+
const nextProjection = projectOperation(dataSource, projectedDocument, toProjectionOperation(item));
|
|
193
|
+
if (!nextProjection) return false;
|
|
194
|
+
projectedDocument = nextProjection;
|
|
195
|
+
return true;
|
|
196
|
+
});
|
|
115
197
|
try {
|
|
116
|
-
|
|
198
|
+
safePayload.forEach((item) => {
|
|
117
199
|
const { action } = item;
|
|
118
200
|
switch (action) {
|
|
119
201
|
case "modify": {
|
|
@@ -142,14 +224,39 @@ function registerLiteXMLCommand(editor, dataSource) {
|
|
|
142
224
|
}
|
|
143
225
|
}, COMMAND_PRIORITY_EDITOR), editor.registerCommand(LITEXML_APPLY_COMMAND, (payload) => {
|
|
144
226
|
const { litexml, delay } = payload;
|
|
145
|
-
|
|
227
|
+
const arrayXml = toArrayXml(litexml);
|
|
228
|
+
if (!delay) {
|
|
229
|
+
handleModify(editor, dataSource, arrayXml, delay);
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
const operation = {
|
|
233
|
+
action: "modify",
|
|
234
|
+
litexml
|
|
235
|
+
};
|
|
236
|
+
if (projectOperation(dataSource, getKernelFromEditor(editor).getDocument("json"), toProjectionOperation(operation))) handleModify(editor, dataSource, arrayXml, delay);
|
|
146
237
|
return false;
|
|
147
238
|
}, COMMAND_PRIORITY_EDITOR), editor.registerCommand(LITEXML_REMOVE_COMMAND, (payload) => {
|
|
148
239
|
const { id, delay } = payload;
|
|
149
|
-
|
|
240
|
+
const key = charToId(id);
|
|
241
|
+
if (!delay) {
|
|
242
|
+
handleRemove(editor, key, delay);
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
const operation = {
|
|
246
|
+
action: "remove",
|
|
247
|
+
id
|
|
248
|
+
};
|
|
249
|
+
if (projectOperation(dataSource, getKernelFromEditor(editor).getDocument("json"), toProjectionOperation(operation))) handleRemove(editor, key, delay);
|
|
150
250
|
return false;
|
|
151
251
|
}, COMMAND_PRIORITY_EDITOR), editor.registerCommand(LITEXML_INSERT_COMMAND, (payload) => {
|
|
152
|
-
|
|
252
|
+
if (!payload.delay) {
|
|
253
|
+
handleInsert(editor, payload, dataSource);
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
if (projectOperation(dataSource, getKernelFromEditor(editor).getDocument("json"), toProjectionOperation({
|
|
257
|
+
action: "insert",
|
|
258
|
+
...payload
|
|
259
|
+
}))) handleInsert(editor, payload, dataSource);
|
|
153
260
|
return false;
|
|
154
261
|
}, COMMAND_PRIORITY_EDITOR));
|
|
155
262
|
}
|
|
@@ -202,9 +309,32 @@ function handleRemove(editor, key, delay) {
|
|
|
202
309
|
const node = $getNodeByKey(key);
|
|
203
310
|
if (!node) return;
|
|
204
311
|
if (!delay) {
|
|
312
|
+
if ($isTableCellNode(node)) {
|
|
313
|
+
const table = $getTableForCell(node);
|
|
314
|
+
const columnIndex = $getTableCellColumnIndex(node);
|
|
315
|
+
const span = node.getColSpan();
|
|
316
|
+
node.remove();
|
|
317
|
+
if (table && columnIndex >= 0) $shrinkTableWidthsAfterCellRemoval(table, columnIndex, span);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
205
320
|
node.remove();
|
|
206
321
|
return;
|
|
207
322
|
}
|
|
323
|
+
if ($isTableCellNode(node)) {
|
|
324
|
+
const table = $getTableForCell(node);
|
|
325
|
+
const columnIndex = $getTableCellColumnIndex(node);
|
|
326
|
+
if (!table || columnIndex < 0) {
|
|
327
|
+
logger.error(`❌ Table cell ${node.getKey()} is not attached to a valid table row.`);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const changeId = `${table.getKey()}:column:${columnIndex}`;
|
|
331
|
+
node.replace($createTableCellDiffFromCell(editor, node, "remove", changeId), false);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if ($isTableRowNode(node) && $isTableNode(node.getParent())) {
|
|
335
|
+
node.replace($createTableRowDiffFromRow(editor, node, "remove"), false);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
208
338
|
if (node.isInline() === false) {
|
|
209
339
|
const originDiffNode = $closest(node, (node) => node.getType() === DiffNode.getType());
|
|
210
340
|
if (originDiffNode) {
|
|
@@ -266,6 +396,38 @@ function handleInsert(editor, payload, dataSource) {
|
|
|
266
396
|
else referenceNode = $getNodeByKey(charToId(payload.afterId));
|
|
267
397
|
if (!referenceNode) throw new Error("Reference node not found for insertion.");
|
|
268
398
|
const newNodes = inode.root.children.map((child) => $parseSerializedNodeImpl(child, editor));
|
|
399
|
+
const referencesTableCell = $isTableCellNode(referenceNode);
|
|
400
|
+
const insertsOnlyTableCells = newNodes.length > 0 && newNodes.every($isTableCellNode);
|
|
401
|
+
if (referencesTableCell || insertsOnlyTableCells) {
|
|
402
|
+
if (!referencesTableCell || !insertsOnlyTableCells) {
|
|
403
|
+
logger.error("❌ Table cells can only be inserted next to another cell in the same row.");
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const cellReference = referenceNode;
|
|
407
|
+
const table = $getTableForCell(cellReference);
|
|
408
|
+
const referenceIndex = $getTableCellColumnIndex(cellReference);
|
|
409
|
+
if (!table || referenceIndex < 0) {
|
|
410
|
+
logger.error("❌ Table cell insertion requires a valid table parent.");
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const rowWidthBefore = $getLogicalRowWidth(cellReference);
|
|
414
|
+
const insertionIndex = isBefore ? referenceIndex : referenceIndex + cellReference.getColSpan();
|
|
415
|
+
const insertedSpan = newNodes.reduce((total, node) => total + ($isTableCellNode(node) ? node.getColSpan() : 0), 0);
|
|
416
|
+
$updateTableWidthsForCellInsertion(table, rowWidthBefore, insertionIndex, insertedSpan);
|
|
417
|
+
let spanOffset = 0;
|
|
418
|
+
const cells = newNodes.map((node) => {
|
|
419
|
+
const result = delay ? $createTableCellDiffFromCell(editor, node, "add", `${table.getKey()}:column:${insertionIndex + spanOffset}`) : node;
|
|
420
|
+
spanOffset += node.getColSpan();
|
|
421
|
+
return result;
|
|
422
|
+
});
|
|
423
|
+
if (isBefore) cells.reverse().forEach((cell) => {
|
|
424
|
+
referenceNode = referenceNode.insertBefore(cell);
|
|
425
|
+
});
|
|
426
|
+
else cells.forEach((cell) => {
|
|
427
|
+
referenceNode = referenceNode.insertAfter(cell);
|
|
428
|
+
});
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
269
431
|
if (!delay) {
|
|
270
432
|
if (isBefore) newNodes.reverse().forEach((node) => {
|
|
271
433
|
referenceNode = referenceNode.insertBefore(node);
|
|
@@ -275,6 +437,25 @@ function handleInsert(editor, payload, dataSource) {
|
|
|
275
437
|
});
|
|
276
438
|
return;
|
|
277
439
|
}
|
|
440
|
+
const referencesTableRow = $isTableRowNode(referenceNode);
|
|
441
|
+
const insertsOnlyTableRows = newNodes.every($isTableRowNode);
|
|
442
|
+
if (referencesTableRow || insertsOnlyTableRows) {
|
|
443
|
+
if (!referencesTableRow || !insertsOnlyTableRows || !$isTableNode(referenceNode.getParent())) {
|
|
444
|
+
logger.error("❌ Table rows can only be inserted next to another row in the same table.");
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
if (isBefore) newNodes.reverse().forEach((node) => {
|
|
448
|
+
if (!$isTableRowNode(node)) return;
|
|
449
|
+
const diffRow = $createTableRowDiffFromRow(editor, node, "add");
|
|
450
|
+
referenceNode = referenceNode.insertBefore(diffRow);
|
|
451
|
+
});
|
|
452
|
+
else newNodes.forEach((node) => {
|
|
453
|
+
if (!$isTableRowNode(node)) return;
|
|
454
|
+
const diffRow = $createTableRowDiffFromRow(editor, node, "add");
|
|
455
|
+
referenceNode = referenceNode.insertAfter(diffRow);
|
|
456
|
+
});
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
278
459
|
if (isBefore) {
|
|
279
460
|
if (referenceNode.isInline() === false) {
|
|
280
461
|
const originDiffNode = $closest(referenceNode, (node) => node.getType() === DiffNode.getType());
|