@tmagic/editor 1.7.14-beta.2 → 1.7.14-beta.3
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/dist/es/services/editor.js +88 -31
- package/dist/tmagic-editor.umd.cjs +88 -31
- package/package.json +7 -7
- package/src/services/editor.ts +132 -40
- package/types/index.d.ts +36 -12
|
@@ -12,6 +12,23 @@ import { NodeType } from "@tmagic/core";
|
|
|
12
12
|
import { reactive, toRaw } from "vue";
|
|
13
13
|
import { cloneDeep, isObject, mergeWith, uniq } from "lodash-es";
|
|
14
14
|
//#region packages/editor/src/services/editor.ts
|
|
15
|
+
/**
|
|
16
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的最后一个形参可能被注入为 dispatch 函数
|
|
17
|
+
* 当 options 形参位置被注入为函数(或为 null)时,将其归一为空对象,避免后续逻辑误读
|
|
18
|
+
*/
|
|
19
|
+
var safeOptions = (options) => {
|
|
20
|
+
const empty = {};
|
|
21
|
+
if (!options || typeof options === "function") return empty;
|
|
22
|
+
return options;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的形参可能被注入为 dispatch 函数
|
|
26
|
+
* 当 parent 形参位置被注入为函数(或为空值)时,归一为 null,由调用方继续走默认 parent 逻辑
|
|
27
|
+
*/
|
|
28
|
+
var safeParent = (parent) => {
|
|
29
|
+
if (!parent || typeof parent === "function") return null;
|
|
30
|
+
return parent;
|
|
31
|
+
};
|
|
15
32
|
var Editor = class extends BaseService_default {
|
|
16
33
|
state = reactive({
|
|
17
34
|
root: null,
|
|
@@ -222,9 +239,13 @@ var Editor = class extends BaseService_default {
|
|
|
222
239
|
* 向指点容器添加组件节点
|
|
223
240
|
* @param addConfig 将要添加的组件节点配置
|
|
224
241
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
242
|
+
* @param options 可选配置
|
|
243
|
+
* @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
|
|
225
244
|
* @returns 添加后的节点
|
|
226
245
|
*/
|
|
227
|
-
async add(addNode, parent) {
|
|
246
|
+
async add(addNode, parent, options) {
|
|
247
|
+
const safeParentNode = safeParent(parent);
|
|
248
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
228
249
|
this.captureSelectionBeforeOp();
|
|
229
250
|
const stage = this.get("stage");
|
|
230
251
|
const addNodes = [];
|
|
@@ -236,19 +257,21 @@ var Editor = class extends BaseService_default {
|
|
|
236
257
|
const newNodes = await Promise.all(addNodes.map((node) => {
|
|
237
258
|
const root = this.get("root");
|
|
238
259
|
if ((isPage(node) || isPageFragment(node)) && root) return this.doAdd(node, root);
|
|
239
|
-
const parentNode =
|
|
260
|
+
const parentNode = safeParentNode ?? getAddParent(node);
|
|
240
261
|
if (!parentNode) throw new Error("未找到父元素");
|
|
241
262
|
return this.doAdd(node, parentNode);
|
|
242
263
|
}));
|
|
243
264
|
if (newNodes.length > 1) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
265
|
+
if (!doNotSelect) {
|
|
266
|
+
const newNodeIds = newNodes.map((node) => node.id);
|
|
267
|
+
stage?.multiSelect(newNodeIds);
|
|
268
|
+
await this.multiSelect(newNodeIds);
|
|
269
|
+
}
|
|
247
270
|
} else {
|
|
248
|
-
await this.select(newNodes[0]);
|
|
271
|
+
if (!doNotSelect) await this.select(newNodes[0]);
|
|
249
272
|
if (isPage(newNodes[0])) this.state.pageLength += 1;
|
|
250
273
|
else if (isPageFragment(newNodes[0])) this.state.pageFragmentLength += 1;
|
|
251
|
-
else stage?.select(newNodes[0].id);
|
|
274
|
+
else if (!doNotSelect) stage?.select(newNodes[0].id);
|
|
252
275
|
}
|
|
253
276
|
if (!(isPage(newNodes[0]) || isPageFragment(newNodes[0]))) {
|
|
254
277
|
const pageForOp = this.getNodeInfo(newNodes[0].id, false).page;
|
|
@@ -267,7 +290,8 @@ var Editor = class extends BaseService_default {
|
|
|
267
290
|
this.emit("add", newNodes);
|
|
268
291
|
return Array.isArray(addNode) ? newNodes : newNodes[0];
|
|
269
292
|
}
|
|
270
|
-
async doRemove(node) {
|
|
293
|
+
async doRemove(node, options) {
|
|
294
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
271
295
|
const root = this.get("root");
|
|
272
296
|
if (!root) throw new Error("root不能为空");
|
|
273
297
|
const { parent, node: curNode } = this.getNodeInfo(node.id, false);
|
|
@@ -281,6 +305,19 @@ var Editor = class extends BaseService_default {
|
|
|
281
305
|
parentId: parent.id,
|
|
282
306
|
root: cloneDeep(root)
|
|
283
307
|
});
|
|
308
|
+
if (doNotSelect) {
|
|
309
|
+
const selectedNodes = this.get("nodes");
|
|
310
|
+
const removedSelectedIndex = selectedNodes.findIndex((n) => `${n.id}` === `${node.id}`);
|
|
311
|
+
if (removedSelectedIndex !== -1) {
|
|
312
|
+
const nextSelected = [...selectedNodes];
|
|
313
|
+
nextSelected.splice(removedSelectedIndex, 1);
|
|
314
|
+
this.set("nodes", nextSelected);
|
|
315
|
+
}
|
|
316
|
+
if (isPage(node) || isPageFragment(node)) {
|
|
317
|
+
const currentPage = this.get("page");
|
|
318
|
+
if (currentPage && `${currentPage.id}` === `${node.id}`) this.set("page", null);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
284
321
|
const selectDefault = async (pages) => {
|
|
285
322
|
if (pages[0]) {
|
|
286
323
|
await this.select(pages[0]);
|
|
@@ -293,13 +330,15 @@ var Editor = class extends BaseService_default {
|
|
|
293
330
|
const rootItems = root.items || [];
|
|
294
331
|
if (isPage(node)) {
|
|
295
332
|
this.state.pageLength -= 1;
|
|
296
|
-
await selectDefault(rootItems);
|
|
333
|
+
if (!doNotSelect) await selectDefault(rootItems);
|
|
297
334
|
} else if (isPageFragment(node)) {
|
|
298
335
|
this.state.pageFragmentLength -= 1;
|
|
299
|
-
await selectDefault(rootItems);
|
|
336
|
+
if (!doNotSelect) await selectDefault(rootItems);
|
|
300
337
|
} else {
|
|
301
|
-
|
|
302
|
-
|
|
338
|
+
if (!doNotSelect) {
|
|
339
|
+
await this.select(parent);
|
|
340
|
+
stage?.select(parent.id);
|
|
341
|
+
}
|
|
303
342
|
this.addModifiedNodeId(parent.id);
|
|
304
343
|
}
|
|
305
344
|
if (!rootItems.length) {
|
|
@@ -309,9 +348,12 @@ var Editor = class extends BaseService_default {
|
|
|
309
348
|
}
|
|
310
349
|
/**
|
|
311
350
|
* 删除组件
|
|
312
|
-
* @param {Object} node
|
|
351
|
+
* @param {Object} node 要删除的节点或节点集合
|
|
352
|
+
* @param options 可选配置
|
|
353
|
+
* @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
|
|
313
354
|
*/
|
|
314
|
-
async remove(nodeOrNodeList) {
|
|
355
|
+
async remove(nodeOrNodeList, options) {
|
|
356
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
315
357
|
this.captureSelectionBeforeOp();
|
|
316
358
|
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
317
359
|
const removedItems = [];
|
|
@@ -331,11 +373,11 @@ var Editor = class extends BaseService_default {
|
|
|
331
373
|
});
|
|
332
374
|
}
|
|
333
375
|
}
|
|
334
|
-
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
376
|
+
await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
|
|
335
377
|
if (removedItems.length > 0 && pageForOp) this.pushOpHistory("remove", { removedItems }, pageForOp);
|
|
336
378
|
this.emit("remove", nodes);
|
|
337
379
|
}
|
|
338
|
-
async doUpdate(config, { changeRecords = []
|
|
380
|
+
async doUpdate(config, { changeRecords = [] } = {}) {
|
|
339
381
|
const root = this.get("root");
|
|
340
382
|
if (!root) throw new Error("root为空");
|
|
341
383
|
if (!config?.id) throw new Error("没有配置或者配置缺少id值");
|
|
@@ -362,11 +404,11 @@ var Editor = class extends BaseService_default {
|
|
|
362
404
|
const layout = await this.getLayout(node);
|
|
363
405
|
if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
|
|
364
406
|
parentNodeItems[index] = newConfig;
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
this.set("nodes", [...
|
|
407
|
+
const selectedNodes = this.get("nodes");
|
|
408
|
+
const targetIndex = selectedNodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
|
|
409
|
+
if (targetIndex !== -1) {
|
|
410
|
+
selectedNodes.splice(targetIndex, 1, newConfig);
|
|
411
|
+
this.set("nodes", [...selectedNodes]);
|
|
370
412
|
}
|
|
371
413
|
if (isPage(newConfig) || isPageFragment(newConfig)) this.set("page", newConfig);
|
|
372
414
|
this.addModifiedNodeId(newConfig.id);
|
|
@@ -407,9 +449,12 @@ var Editor = class extends BaseService_default {
|
|
|
407
449
|
* 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
|
|
408
450
|
* @param id1 组件ID
|
|
409
451
|
* @param id2 组件ID
|
|
452
|
+
* @param options 可选配置
|
|
453
|
+
* @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
|
|
410
454
|
* @returns void
|
|
411
455
|
*/
|
|
412
|
-
async sort(id1, id2) {
|
|
456
|
+
async sort(id1, id2, options) {
|
|
457
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
413
458
|
this.captureSelectionBeforeOp();
|
|
414
459
|
const root = this.get("root");
|
|
415
460
|
if (!root) throw new Error("root为空");
|
|
@@ -422,7 +467,7 @@ var Editor = class extends BaseService_default {
|
|
|
422
467
|
const index1 = parent.items.findIndex((node) => `${node.id}` === `${id1}`);
|
|
423
468
|
parent.items.splice(index2, 0, ...parent.items.splice(index1, 1));
|
|
424
469
|
await this.update(parent);
|
|
425
|
-
await this.select(node);
|
|
470
|
+
if (!doNotSelect) await this.select(node);
|
|
426
471
|
this.get("stage")?.update({
|
|
427
472
|
config: cloneDeep(node),
|
|
428
473
|
parentId: parent.id,
|
|
@@ -450,9 +495,13 @@ var Editor = class extends BaseService_default {
|
|
|
450
495
|
/**
|
|
451
496
|
* 从localStorage中获取节点,然后添加到当前容器中
|
|
452
497
|
* @param position 粘贴的坐标
|
|
498
|
+
* @param collectorOptions 可选的依赖收集器配置
|
|
499
|
+
* @param options 可选配置
|
|
500
|
+
* @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
|
|
453
501
|
* @returns 添加后的组件节点配置
|
|
454
502
|
*/
|
|
455
|
-
async paste(position = {}, collectorOptions) {
|
|
503
|
+
async paste(position = {}, collectorOptions, options) {
|
|
504
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
456
505
|
const config = storage_default.getItem(COPY_STORAGE_KEY);
|
|
457
506
|
if (!Array.isArray(config)) return;
|
|
458
507
|
const node = this.get("node");
|
|
@@ -463,7 +512,7 @@ var Editor = class extends BaseService_default {
|
|
|
463
512
|
}
|
|
464
513
|
const pasteConfigs = await this.doPaste(config, position);
|
|
465
514
|
if (collectorOptions && typeof collectorOptions.isTarget === "function") props_default.replaceRelateId(config, pasteConfigs, collectorOptions);
|
|
466
|
-
return this.add(pasteConfigs, parent);
|
|
515
|
+
return this.add(pasteConfigs, parent, { doNotSelect });
|
|
467
516
|
}
|
|
468
517
|
async doPaste(config, position = {}) {
|
|
469
518
|
props_default.clearRelateId();
|
|
@@ -484,14 +533,17 @@ var Editor = class extends BaseService_default {
|
|
|
484
533
|
/**
|
|
485
534
|
* 将指点节点设置居中
|
|
486
535
|
* @param config 组件节点配置
|
|
536
|
+
* @param options 可选配置
|
|
537
|
+
* @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
|
|
487
538
|
* @returns 当前组件节点配置
|
|
488
539
|
*/
|
|
489
|
-
async alignCenter(config) {
|
|
540
|
+
async alignCenter(config, options) {
|
|
541
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
490
542
|
const nodes = Array.isArray(config) ? config : [config];
|
|
491
543
|
const stage = this.get("stage");
|
|
492
544
|
const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
|
|
493
545
|
const newNode = await this.update(newNodes);
|
|
494
|
-
if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
546
|
+
if (!doNotSelect) if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
495
547
|
else await stage?.select(newNodes[0].id);
|
|
496
548
|
return newNode;
|
|
497
549
|
}
|
|
@@ -536,8 +588,11 @@ var Editor = class extends BaseService_default {
|
|
|
536
588
|
* 移动到指定容器中
|
|
537
589
|
* @param config 需要移动的节点
|
|
538
590
|
* @param targetId 容器ID
|
|
591
|
+
* @param options 可选配置
|
|
592
|
+
* @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
|
|
539
593
|
*/
|
|
540
|
-
async moveToContainer(config, targetId) {
|
|
594
|
+
async moveToContainer(config, targetId, options) {
|
|
595
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
541
596
|
this.captureSelectionBeforeOp();
|
|
542
597
|
const root = this.get("root");
|
|
543
598
|
const { node, parent, page: pageForOp } = this.getNodeInfo(config.id, false);
|
|
@@ -559,15 +614,17 @@ var Editor = class extends BaseService_default {
|
|
|
559
614
|
});
|
|
560
615
|
newConfig.style = getInitPositionStyle(newConfig.style, layout);
|
|
561
616
|
target.items.push(newConfig);
|
|
562
|
-
await stage.select(targetId);
|
|
617
|
+
if (!doNotSelect) await stage.select(targetId);
|
|
563
618
|
const targetParent = this.getParentById(target.id);
|
|
564
619
|
await stage.update({
|
|
565
620
|
config: cloneDeep(target),
|
|
566
621
|
parentId: targetParent?.id,
|
|
567
622
|
root: cloneDeep(root)
|
|
568
623
|
});
|
|
569
|
-
|
|
570
|
-
|
|
624
|
+
if (!doNotSelect) {
|
|
625
|
+
await this.select(newConfig);
|
|
626
|
+
stage.select(newConfig.id);
|
|
627
|
+
}
|
|
571
628
|
this.addModifiedNodeId(target.id);
|
|
572
629
|
this.addModifiedNodeId(parent.id);
|
|
573
630
|
this.pushOpHistory("update", { updatedItems: [{
|
|
@@ -5793,6 +5793,23 @@
|
|
|
5793
5793
|
};
|
|
5794
5794
|
//#endregion
|
|
5795
5795
|
//#region packages/editor/src/services/editor.ts
|
|
5796
|
+
/**
|
|
5797
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的最后一个形参可能被注入为 dispatch 函数
|
|
5798
|
+
* 当 options 形参位置被注入为函数(或为 null)时,将其归一为空对象,避免后续逻辑误读
|
|
5799
|
+
*/
|
|
5800
|
+
var safeOptions = (options) => {
|
|
5801
|
+
const empty = {};
|
|
5802
|
+
if (!options || typeof options === "function") return empty;
|
|
5803
|
+
return options;
|
|
5804
|
+
};
|
|
5805
|
+
/**
|
|
5806
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的形参可能被注入为 dispatch 函数
|
|
5807
|
+
* 当 parent 形参位置被注入为函数(或为空值)时,归一为 null,由调用方继续走默认 parent 逻辑
|
|
5808
|
+
*/
|
|
5809
|
+
var safeParent = (parent) => {
|
|
5810
|
+
if (!parent || typeof parent === "function") return null;
|
|
5811
|
+
return parent;
|
|
5812
|
+
};
|
|
5796
5813
|
var Editor = class extends BaseService_default {
|
|
5797
5814
|
state = (0, vue.reactive)({
|
|
5798
5815
|
root: null,
|
|
@@ -6003,9 +6020,13 @@
|
|
|
6003
6020
|
* 向指点容器添加组件节点
|
|
6004
6021
|
* @param addConfig 将要添加的组件节点配置
|
|
6005
6022
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
6023
|
+
* @param options 可选配置
|
|
6024
|
+
* @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
|
|
6006
6025
|
* @returns 添加后的节点
|
|
6007
6026
|
*/
|
|
6008
|
-
async add(addNode, parent) {
|
|
6027
|
+
async add(addNode, parent, options) {
|
|
6028
|
+
const safeParentNode = safeParent(parent);
|
|
6029
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
6009
6030
|
this.captureSelectionBeforeOp();
|
|
6010
6031
|
const stage = this.get("stage");
|
|
6011
6032
|
const addNodes = [];
|
|
@@ -6017,19 +6038,21 @@
|
|
|
6017
6038
|
const newNodes = await Promise.all(addNodes.map((node) => {
|
|
6018
6039
|
const root = this.get("root");
|
|
6019
6040
|
if (((0, _tmagic_utils.isPage)(node) || (0, _tmagic_utils.isPageFragment)(node)) && root) return this.doAdd(node, root);
|
|
6020
|
-
const parentNode =
|
|
6041
|
+
const parentNode = safeParentNode ?? getAddParent(node);
|
|
6021
6042
|
if (!parentNode) throw new Error("未找到父元素");
|
|
6022
6043
|
return this.doAdd(node, parentNode);
|
|
6023
6044
|
}));
|
|
6024
6045
|
if (newNodes.length > 1) {
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6046
|
+
if (!doNotSelect) {
|
|
6047
|
+
const newNodeIds = newNodes.map((node) => node.id);
|
|
6048
|
+
stage?.multiSelect(newNodeIds);
|
|
6049
|
+
await this.multiSelect(newNodeIds);
|
|
6050
|
+
}
|
|
6028
6051
|
} else {
|
|
6029
|
-
await this.select(newNodes[0]);
|
|
6052
|
+
if (!doNotSelect) await this.select(newNodes[0]);
|
|
6030
6053
|
if ((0, _tmagic_utils.isPage)(newNodes[0])) this.state.pageLength += 1;
|
|
6031
6054
|
else if ((0, _tmagic_utils.isPageFragment)(newNodes[0])) this.state.pageFragmentLength += 1;
|
|
6032
|
-
else stage?.select(newNodes[0].id);
|
|
6055
|
+
else if (!doNotSelect) stage?.select(newNodes[0].id);
|
|
6033
6056
|
}
|
|
6034
6057
|
if (!((0, _tmagic_utils.isPage)(newNodes[0]) || (0, _tmagic_utils.isPageFragment)(newNodes[0]))) {
|
|
6035
6058
|
const pageForOp = this.getNodeInfo(newNodes[0].id, false).page;
|
|
@@ -6048,7 +6071,8 @@
|
|
|
6048
6071
|
this.emit("add", newNodes);
|
|
6049
6072
|
return Array.isArray(addNode) ? newNodes : newNodes[0];
|
|
6050
6073
|
}
|
|
6051
|
-
async doRemove(node) {
|
|
6074
|
+
async doRemove(node, options) {
|
|
6075
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
6052
6076
|
const root = this.get("root");
|
|
6053
6077
|
if (!root) throw new Error("root不能为空");
|
|
6054
6078
|
const { parent, node: curNode } = this.getNodeInfo(node.id, false);
|
|
@@ -6062,6 +6086,19 @@
|
|
|
6062
6086
|
parentId: parent.id,
|
|
6063
6087
|
root: cloneDeep(root)
|
|
6064
6088
|
});
|
|
6089
|
+
if (doNotSelect) {
|
|
6090
|
+
const selectedNodes = this.get("nodes");
|
|
6091
|
+
const removedSelectedIndex = selectedNodes.findIndex((n) => `${n.id}` === `${node.id}`);
|
|
6092
|
+
if (removedSelectedIndex !== -1) {
|
|
6093
|
+
const nextSelected = [...selectedNodes];
|
|
6094
|
+
nextSelected.splice(removedSelectedIndex, 1);
|
|
6095
|
+
this.set("nodes", nextSelected);
|
|
6096
|
+
}
|
|
6097
|
+
if ((0, _tmagic_utils.isPage)(node) || (0, _tmagic_utils.isPageFragment)(node)) {
|
|
6098
|
+
const currentPage = this.get("page");
|
|
6099
|
+
if (currentPage && `${currentPage.id}` === `${node.id}`) this.set("page", null);
|
|
6100
|
+
}
|
|
6101
|
+
}
|
|
6065
6102
|
const selectDefault = async (pages) => {
|
|
6066
6103
|
if (pages[0]) {
|
|
6067
6104
|
await this.select(pages[0]);
|
|
@@ -6074,13 +6111,15 @@
|
|
|
6074
6111
|
const rootItems = root.items || [];
|
|
6075
6112
|
if ((0, _tmagic_utils.isPage)(node)) {
|
|
6076
6113
|
this.state.pageLength -= 1;
|
|
6077
|
-
await selectDefault(rootItems);
|
|
6114
|
+
if (!doNotSelect) await selectDefault(rootItems);
|
|
6078
6115
|
} else if ((0, _tmagic_utils.isPageFragment)(node)) {
|
|
6079
6116
|
this.state.pageFragmentLength -= 1;
|
|
6080
|
-
await selectDefault(rootItems);
|
|
6117
|
+
if (!doNotSelect) await selectDefault(rootItems);
|
|
6081
6118
|
} else {
|
|
6082
|
-
|
|
6083
|
-
|
|
6119
|
+
if (!doNotSelect) {
|
|
6120
|
+
await this.select(parent);
|
|
6121
|
+
stage?.select(parent.id);
|
|
6122
|
+
}
|
|
6084
6123
|
this.addModifiedNodeId(parent.id);
|
|
6085
6124
|
}
|
|
6086
6125
|
if (!rootItems.length) {
|
|
@@ -6090,9 +6129,12 @@
|
|
|
6090
6129
|
}
|
|
6091
6130
|
/**
|
|
6092
6131
|
* 删除组件
|
|
6093
|
-
* @param {Object} node
|
|
6132
|
+
* @param {Object} node 要删除的节点或节点集合
|
|
6133
|
+
* @param options 可选配置
|
|
6134
|
+
* @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
|
|
6094
6135
|
*/
|
|
6095
|
-
async remove(nodeOrNodeList) {
|
|
6136
|
+
async remove(nodeOrNodeList, options) {
|
|
6137
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
6096
6138
|
this.captureSelectionBeforeOp();
|
|
6097
6139
|
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
6098
6140
|
const removedItems = [];
|
|
@@ -6112,11 +6154,11 @@
|
|
|
6112
6154
|
});
|
|
6113
6155
|
}
|
|
6114
6156
|
}
|
|
6115
|
-
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
6157
|
+
await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
|
|
6116
6158
|
if (removedItems.length > 0 && pageForOp) this.pushOpHistory("remove", { removedItems }, pageForOp);
|
|
6117
6159
|
this.emit("remove", nodes);
|
|
6118
6160
|
}
|
|
6119
|
-
async doUpdate(config, { changeRecords = []
|
|
6161
|
+
async doUpdate(config, { changeRecords = [] } = {}) {
|
|
6120
6162
|
const root = this.get("root");
|
|
6121
6163
|
if (!root) throw new Error("root为空");
|
|
6122
6164
|
if (!config?.id) throw new Error("没有配置或者配置缺少id值");
|
|
@@ -6143,11 +6185,11 @@
|
|
|
6143
6185
|
const layout = await this.getLayout(node);
|
|
6144
6186
|
if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
|
|
6145
6187
|
parentNodeItems[index] = newConfig;
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
this.set("nodes", [...
|
|
6188
|
+
const selectedNodes = this.get("nodes");
|
|
6189
|
+
const targetIndex = selectedNodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
|
|
6190
|
+
if (targetIndex !== -1) {
|
|
6191
|
+
selectedNodes.splice(targetIndex, 1, newConfig);
|
|
6192
|
+
this.set("nodes", [...selectedNodes]);
|
|
6151
6193
|
}
|
|
6152
6194
|
if ((0, _tmagic_utils.isPage)(newConfig) || (0, _tmagic_utils.isPageFragment)(newConfig)) this.set("page", newConfig);
|
|
6153
6195
|
this.addModifiedNodeId(newConfig.id);
|
|
@@ -6188,9 +6230,12 @@
|
|
|
6188
6230
|
* 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
|
|
6189
6231
|
* @param id1 组件ID
|
|
6190
6232
|
* @param id2 组件ID
|
|
6233
|
+
* @param options 可选配置
|
|
6234
|
+
* @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
|
|
6191
6235
|
* @returns void
|
|
6192
6236
|
*/
|
|
6193
|
-
async sort(id1, id2) {
|
|
6237
|
+
async sort(id1, id2, options) {
|
|
6238
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
6194
6239
|
this.captureSelectionBeforeOp();
|
|
6195
6240
|
const root = this.get("root");
|
|
6196
6241
|
if (!root) throw new Error("root为空");
|
|
@@ -6203,7 +6248,7 @@
|
|
|
6203
6248
|
const index1 = parent.items.findIndex((node) => `${node.id}` === `${id1}`);
|
|
6204
6249
|
parent.items.splice(index2, 0, ...parent.items.splice(index1, 1));
|
|
6205
6250
|
await this.update(parent);
|
|
6206
|
-
await this.select(node);
|
|
6251
|
+
if (!doNotSelect) await this.select(node);
|
|
6207
6252
|
this.get("stage")?.update({
|
|
6208
6253
|
config: cloneDeep(node),
|
|
6209
6254
|
parentId: parent.id,
|
|
@@ -6231,9 +6276,13 @@
|
|
|
6231
6276
|
/**
|
|
6232
6277
|
* 从localStorage中获取节点,然后添加到当前容器中
|
|
6233
6278
|
* @param position 粘贴的坐标
|
|
6279
|
+
* @param collectorOptions 可选的依赖收集器配置
|
|
6280
|
+
* @param options 可选配置
|
|
6281
|
+
* @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
|
|
6234
6282
|
* @returns 添加后的组件节点配置
|
|
6235
6283
|
*/
|
|
6236
|
-
async paste(position = {}, collectorOptions) {
|
|
6284
|
+
async paste(position = {}, collectorOptions, options) {
|
|
6285
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
6237
6286
|
const config = storage_default.getItem(COPY_STORAGE_KEY);
|
|
6238
6287
|
if (!Array.isArray(config)) return;
|
|
6239
6288
|
const node = this.get("node");
|
|
@@ -6244,7 +6293,7 @@
|
|
|
6244
6293
|
}
|
|
6245
6294
|
const pasteConfigs = await this.doPaste(config, position);
|
|
6246
6295
|
if (collectorOptions && typeof collectorOptions.isTarget === "function") props_default.replaceRelateId(config, pasteConfigs, collectorOptions);
|
|
6247
|
-
return this.add(pasteConfigs, parent);
|
|
6296
|
+
return this.add(pasteConfigs, parent, { doNotSelect });
|
|
6248
6297
|
}
|
|
6249
6298
|
async doPaste(config, position = {}) {
|
|
6250
6299
|
props_default.clearRelateId();
|
|
@@ -6265,14 +6314,17 @@
|
|
|
6265
6314
|
/**
|
|
6266
6315
|
* 将指点节点设置居中
|
|
6267
6316
|
* @param config 组件节点配置
|
|
6317
|
+
* @param options 可选配置
|
|
6318
|
+
* @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
|
|
6268
6319
|
* @returns 当前组件节点配置
|
|
6269
6320
|
*/
|
|
6270
|
-
async alignCenter(config) {
|
|
6321
|
+
async alignCenter(config, options) {
|
|
6322
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
6271
6323
|
const nodes = Array.isArray(config) ? config : [config];
|
|
6272
6324
|
const stage = this.get("stage");
|
|
6273
6325
|
const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
|
|
6274
6326
|
const newNode = await this.update(newNodes);
|
|
6275
|
-
if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
6327
|
+
if (!doNotSelect) if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
6276
6328
|
else await stage?.select(newNodes[0].id);
|
|
6277
6329
|
return newNode;
|
|
6278
6330
|
}
|
|
@@ -6317,8 +6369,11 @@
|
|
|
6317
6369
|
* 移动到指定容器中
|
|
6318
6370
|
* @param config 需要移动的节点
|
|
6319
6371
|
* @param targetId 容器ID
|
|
6372
|
+
* @param options 可选配置
|
|
6373
|
+
* @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
|
|
6320
6374
|
*/
|
|
6321
|
-
async moveToContainer(config, targetId) {
|
|
6375
|
+
async moveToContainer(config, targetId, options) {
|
|
6376
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
6322
6377
|
this.captureSelectionBeforeOp();
|
|
6323
6378
|
const root = this.get("root");
|
|
6324
6379
|
const { node, parent, page: pageForOp } = this.getNodeInfo(config.id, false);
|
|
@@ -6340,15 +6395,17 @@
|
|
|
6340
6395
|
});
|
|
6341
6396
|
newConfig.style = getInitPositionStyle(newConfig.style, layout);
|
|
6342
6397
|
target.items.push(newConfig);
|
|
6343
|
-
await stage.select(targetId);
|
|
6398
|
+
if (!doNotSelect) await stage.select(targetId);
|
|
6344
6399
|
const targetParent = this.getParentById(target.id);
|
|
6345
6400
|
await stage.update({
|
|
6346
6401
|
config: cloneDeep(target),
|
|
6347
6402
|
parentId: targetParent?.id,
|
|
6348
6403
|
root: cloneDeep(root)
|
|
6349
6404
|
});
|
|
6350
|
-
|
|
6351
|
-
|
|
6405
|
+
if (!doNotSelect) {
|
|
6406
|
+
await this.select(newConfig);
|
|
6407
|
+
stage.select(newConfig.id);
|
|
6408
|
+
}
|
|
6352
6409
|
this.addModifiedNodeId(target.id);
|
|
6353
6410
|
this.addModifiedNodeId(parent.id);
|
|
6354
6411
|
this.pushOpHistory("update", { updatedItems: [{
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.7.14-beta.
|
|
2
|
+
"version": "1.7.14-beta.3",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
"moveable": "^0.53.0",
|
|
59
59
|
"serialize-javascript": "^7.0.0",
|
|
60
60
|
"sortablejs": "^1.15.6",
|
|
61
|
-
"@tmagic/design": "1.7.14-beta.
|
|
62
|
-
"@tmagic/form": "1.7.14-beta.
|
|
63
|
-
"@tmagic/stage": "1.7.14-beta.
|
|
64
|
-
"@tmagic/table": "1.7.14-beta.
|
|
65
|
-
"@tmagic/utils": "1.7.14-beta.
|
|
61
|
+
"@tmagic/design": "1.7.14-beta.3",
|
|
62
|
+
"@tmagic/form": "1.7.14-beta.3",
|
|
63
|
+
"@tmagic/stage": "1.7.14-beta.3",
|
|
64
|
+
"@tmagic/table": "1.7.14-beta.3",
|
|
65
|
+
"@tmagic/utils": "1.7.14-beta.3"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@types/events": "^3.0.3",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"type-fest": "^5.2.0",
|
|
77
77
|
"typescript": "^6.0.3",
|
|
78
78
|
"vue": "^3.5.34",
|
|
79
|
-
"@tmagic/core": "1.7.14-beta.
|
|
79
|
+
"@tmagic/core": "1.7.14-beta.3"
|
|
80
80
|
},
|
|
81
81
|
"peerDependenciesMeta": {
|
|
82
82
|
"typescript": {
|
package/src/services/editor.ts
CHANGED
|
@@ -65,6 +65,25 @@ import type { HistoryOpContext } from '@editor/utils/editor-history';
|
|
|
65
65
|
import { applyHistoryAddOp, applyHistoryRemoveOp, applyHistoryUpdateOp } from '@editor/utils/editor-history';
|
|
66
66
|
import { beforePaste, getAddParent } from '@editor/utils/operator';
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的最后一个形参可能被注入为 dispatch 函数
|
|
70
|
+
* 当 options 形参位置被注入为函数(或为 null)时,将其归一为空对象,避免后续逻辑误读
|
|
71
|
+
*/
|
|
72
|
+
const safeOptions = <T extends object>(options: unknown): T => {
|
|
73
|
+
const empty = {};
|
|
74
|
+
if (!options || typeof options === 'function') return empty as T;
|
|
75
|
+
return options as T;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的形参可能被注入为 dispatch 函数
|
|
80
|
+
* 当 parent 形参位置被注入为函数(或为空值)时,归一为 null,由调用方继续走默认 parent 逻辑
|
|
81
|
+
*/
|
|
82
|
+
const safeParent = (parent: unknown): MContainer | null => {
|
|
83
|
+
if (!parent || typeof parent === 'function') return null;
|
|
84
|
+
return parent as MContainer;
|
|
85
|
+
};
|
|
86
|
+
|
|
68
87
|
class Editor extends BaseService {
|
|
69
88
|
public state: StoreState = reactive({
|
|
70
89
|
root: null,
|
|
@@ -349,9 +368,18 @@ class Editor extends BaseService {
|
|
|
349
368
|
* 向指点容器添加组件节点
|
|
350
369
|
* @param addConfig 将要添加的组件节点配置
|
|
351
370
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
371
|
+
* @param options 可选配置
|
|
372
|
+
* @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
|
|
352
373
|
* @returns 添加后的节点
|
|
353
374
|
*/
|
|
354
|
-
public async add(
|
|
375
|
+
public async add(
|
|
376
|
+
addNode: AddMNode | MNode[],
|
|
377
|
+
parent?: MContainer | null,
|
|
378
|
+
options?: { doNotSelect?: boolean },
|
|
379
|
+
): Promise<MNode | MNode[]> {
|
|
380
|
+
const safeParentNode = safeParent(parent);
|
|
381
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
382
|
+
|
|
355
383
|
this.captureSelectionBeforeOp();
|
|
356
384
|
|
|
357
385
|
const stage = this.get('stage');
|
|
@@ -374,25 +402,29 @@ class Editor extends BaseService {
|
|
|
374
402
|
if ((isPage(node) || isPageFragment(node)) && root) {
|
|
375
403
|
return this.doAdd(node, root);
|
|
376
404
|
}
|
|
377
|
-
const parentNode =
|
|
405
|
+
const parentNode = safeParentNode ?? getAddParent(node);
|
|
378
406
|
if (!parentNode) throw new Error('未找到父元素');
|
|
379
407
|
return this.doAdd(node, parentNode);
|
|
380
408
|
}),
|
|
381
409
|
);
|
|
382
410
|
|
|
383
411
|
if (newNodes.length > 1) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
412
|
+
if (!doNotSelect) {
|
|
413
|
+
const newNodeIds = newNodes.map((node) => node.id);
|
|
414
|
+
// 触发选中样式
|
|
415
|
+
stage?.multiSelect(newNodeIds);
|
|
416
|
+
await this.multiSelect(newNodeIds);
|
|
417
|
+
}
|
|
388
418
|
} else {
|
|
389
|
-
|
|
419
|
+
if (!doNotSelect) {
|
|
420
|
+
await this.select(newNodes[0]);
|
|
421
|
+
}
|
|
390
422
|
|
|
391
423
|
if (isPage(newNodes[0])) {
|
|
392
424
|
this.state.pageLength += 1;
|
|
393
425
|
} else if (isPageFragment(newNodes[0])) {
|
|
394
426
|
this.state.pageFragmentLength += 1;
|
|
395
|
-
} else {
|
|
427
|
+
} else if (!doNotSelect) {
|
|
396
428
|
// 新增页面,这个时候页面还有渲染出来,此时select会出错,在runtime-ready的时候回去select
|
|
397
429
|
stage?.select(newNodes[0].id);
|
|
398
430
|
}
|
|
@@ -421,7 +453,9 @@ class Editor extends BaseService {
|
|
|
421
453
|
return Array.isArray(addNode) ? newNodes : newNodes[0];
|
|
422
454
|
}
|
|
423
455
|
|
|
424
|
-
public async doRemove(node: MNode): Promise<void> {
|
|
456
|
+
public async doRemove(node: MNode, options?: { doNotSelect?: boolean }): Promise<void> {
|
|
457
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
458
|
+
|
|
425
459
|
const root = this.get('root');
|
|
426
460
|
if (!root) throw new Error('root不能为空');
|
|
427
461
|
|
|
@@ -437,6 +471,24 @@ class Editor extends BaseService {
|
|
|
437
471
|
const stage = this.get('stage');
|
|
438
472
|
stage?.remove({ id: node.id, parentId: parent.id, root: cloneDeep(root) });
|
|
439
473
|
|
|
474
|
+
if (doNotSelect) {
|
|
475
|
+
// 当被删除节点正好在当前选中列表中时,必须从 state 中移除引用,避免 state 持有已删除节点(与 doNotSelect 无关)
|
|
476
|
+
const selectedNodes = this.get('nodes');
|
|
477
|
+
const removedSelectedIndex = selectedNodes.findIndex((n: MNode) => `${n.id}` === `${node.id}`);
|
|
478
|
+
if (removedSelectedIndex !== -1) {
|
|
479
|
+
const nextSelected = [...selectedNodes];
|
|
480
|
+
nextSelected.splice(removedSelectedIndex, 1);
|
|
481
|
+
this.set('nodes', nextSelected);
|
|
482
|
+
}
|
|
483
|
+
// 同理,如果被删除的是当前 page,也清空 state.page,避免持有已删除页面
|
|
484
|
+
if (isPage(node) || isPageFragment(node)) {
|
|
485
|
+
const currentPage = this.get('page');
|
|
486
|
+
if (currentPage && `${currentPage.id}` === `${node.id}`) {
|
|
487
|
+
this.set('page', null);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
440
492
|
const selectDefault = async (pages: MNode[]) => {
|
|
441
493
|
if (pages[0]) {
|
|
442
494
|
await this.select(pages[0]);
|
|
@@ -453,14 +505,20 @@ class Editor extends BaseService {
|
|
|
453
505
|
if (isPage(node)) {
|
|
454
506
|
this.state.pageLength -= 1;
|
|
455
507
|
|
|
456
|
-
|
|
508
|
+
if (!doNotSelect) {
|
|
509
|
+
await selectDefault(rootItems);
|
|
510
|
+
}
|
|
457
511
|
} else if (isPageFragment(node)) {
|
|
458
512
|
this.state.pageFragmentLength -= 1;
|
|
459
513
|
|
|
460
|
-
|
|
514
|
+
if (!doNotSelect) {
|
|
515
|
+
await selectDefault(rootItems);
|
|
516
|
+
}
|
|
461
517
|
} else {
|
|
462
|
-
|
|
463
|
-
|
|
518
|
+
if (!doNotSelect) {
|
|
519
|
+
await this.select(parent);
|
|
520
|
+
stage?.select(parent.id);
|
|
521
|
+
}
|
|
464
522
|
|
|
465
523
|
this.addModifiedNodeId(parent.id);
|
|
466
524
|
}
|
|
@@ -473,9 +531,13 @@ class Editor extends BaseService {
|
|
|
473
531
|
|
|
474
532
|
/**
|
|
475
533
|
* 删除组件
|
|
476
|
-
* @param {Object} node
|
|
534
|
+
* @param {Object} node 要删除的节点或节点集合
|
|
535
|
+
* @param options 可选配置
|
|
536
|
+
* @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
|
|
477
537
|
*/
|
|
478
|
-
public async remove(nodeOrNodeList: MNode | MNode[]): Promise<void> {
|
|
538
|
+
public async remove(nodeOrNodeList: MNode | MNode[], options?: { doNotSelect?: boolean }): Promise<void> {
|
|
539
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
540
|
+
|
|
479
541
|
this.captureSelectionBeforeOp();
|
|
480
542
|
|
|
481
543
|
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
@@ -499,7 +561,7 @@ class Editor extends BaseService {
|
|
|
499
561
|
}
|
|
500
562
|
}
|
|
501
563
|
|
|
502
|
-
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
564
|
+
await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
|
|
503
565
|
|
|
504
566
|
if (removedItems.length > 0 && pageForOp) {
|
|
505
567
|
this.pushOpHistory('remove', { removedItems }, pageForOp);
|
|
@@ -510,10 +572,7 @@ class Editor extends BaseService {
|
|
|
510
572
|
|
|
511
573
|
public async doUpdate(
|
|
512
574
|
config: MNode,
|
|
513
|
-
{
|
|
514
|
-
changeRecords = [],
|
|
515
|
-
selectedAfterUpdate = true,
|
|
516
|
-
}: { changeRecords?: ChangeRecord[]; selectedAfterUpdate?: boolean } = {},
|
|
575
|
+
{ changeRecords = [] }: { changeRecords?: ChangeRecord[] } = {},
|
|
517
576
|
): Promise<{ newNode: MNode; oldNode: MNode; changeRecords?: ChangeRecord[] }> {
|
|
518
577
|
const root = this.get('root');
|
|
519
578
|
if (!root) throw new Error('root为空');
|
|
@@ -557,12 +616,12 @@ class Editor extends BaseService {
|
|
|
557
616
|
|
|
558
617
|
parentNodeItems[index] = newConfig;
|
|
559
618
|
|
|
560
|
-
//
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
this.set('nodes', [...
|
|
619
|
+
// 当被更新节点正好在当前选中列表中时,必须同步引用,否则 state 会持有已被替换的旧节点
|
|
620
|
+
const selectedNodes = this.get('nodes');
|
|
621
|
+
const targetIndex = selectedNodes.findIndex((nodeItem: MNode) => `${nodeItem.id}` === `${newConfig.id}`);
|
|
622
|
+
if (targetIndex !== -1) {
|
|
623
|
+
selectedNodes.splice(targetIndex, 1, newConfig);
|
|
624
|
+
this.set('nodes', [...selectedNodes]);
|
|
566
625
|
}
|
|
567
626
|
|
|
568
627
|
if (isPage(newConfig) || isPageFragment(newConfig)) {
|
|
@@ -586,7 +645,7 @@ class Editor extends BaseService {
|
|
|
586
645
|
*/
|
|
587
646
|
public async update(
|
|
588
647
|
config: MNode | MNode[],
|
|
589
|
-
data: { changeRecords?: ChangeRecord[]
|
|
648
|
+
data: { changeRecords?: ChangeRecord[] } = {},
|
|
590
649
|
): Promise<MNode | MNode[]> {
|
|
591
650
|
this.captureSelectionBeforeOp();
|
|
592
651
|
|
|
@@ -620,9 +679,13 @@ class Editor extends BaseService {
|
|
|
620
679
|
* 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
|
|
621
680
|
* @param id1 组件ID
|
|
622
681
|
* @param id2 组件ID
|
|
682
|
+
* @param options 可选配置
|
|
683
|
+
* @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
|
|
623
684
|
* @returns void
|
|
624
685
|
*/
|
|
625
|
-
public async sort(id1: Id, id2: Id): Promise<void> {
|
|
686
|
+
public async sort(id1: Id, id2: Id, options?: { doNotSelect?: boolean }): Promise<void> {
|
|
687
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
688
|
+
|
|
626
689
|
this.captureSelectionBeforeOp();
|
|
627
690
|
|
|
628
691
|
const root = this.get('root');
|
|
@@ -642,7 +705,9 @@ class Editor extends BaseService {
|
|
|
642
705
|
parent.items.splice(index2, 0, ...parent.items.splice(index1, 1));
|
|
643
706
|
|
|
644
707
|
await this.update(parent);
|
|
645
|
-
|
|
708
|
+
if (!doNotSelect) {
|
|
709
|
+
await this.select(node);
|
|
710
|
+
}
|
|
646
711
|
|
|
647
712
|
this.get('stage')?.update({
|
|
648
713
|
config: cloneDeep(node),
|
|
@@ -682,9 +747,18 @@ class Editor extends BaseService {
|
|
|
682
747
|
/**
|
|
683
748
|
* 从localStorage中获取节点,然后添加到当前容器中
|
|
684
749
|
* @param position 粘贴的坐标
|
|
750
|
+
* @param collectorOptions 可选的依赖收集器配置
|
|
751
|
+
* @param options 可选配置
|
|
752
|
+
* @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
|
|
685
753
|
* @returns 添加后的组件节点配置
|
|
686
754
|
*/
|
|
687
|
-
public async paste(
|
|
755
|
+
public async paste(
|
|
756
|
+
position: PastePosition = {},
|
|
757
|
+
collectorOptions?: TargetOptions,
|
|
758
|
+
options?: { doNotSelect?: boolean },
|
|
759
|
+
): Promise<MNode | MNode[] | void> {
|
|
760
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
761
|
+
|
|
688
762
|
const config: MNode[] = storageService.getItem(COPY_STORAGE_KEY);
|
|
689
763
|
if (!Array.isArray(config)) return;
|
|
690
764
|
|
|
@@ -704,7 +778,7 @@ class Editor extends BaseService {
|
|
|
704
778
|
propsService.replaceRelateId(config, pasteConfigs, collectorOptions);
|
|
705
779
|
}
|
|
706
780
|
|
|
707
|
-
return this.add(pasteConfigs, parent);
|
|
781
|
+
return this.add(pasteConfigs, parent, { doNotSelect });
|
|
708
782
|
}
|
|
709
783
|
|
|
710
784
|
public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
|
|
@@ -732,9 +806,13 @@ class Editor extends BaseService {
|
|
|
732
806
|
/**
|
|
733
807
|
* 将指点节点设置居中
|
|
734
808
|
* @param config 组件节点配置
|
|
809
|
+
* @param options 可选配置
|
|
810
|
+
* @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
|
|
735
811
|
* @returns 当前组件节点配置
|
|
736
812
|
*/
|
|
737
|
-
public async alignCenter(config: MNode | MNode[]): Promise<MNode | MNode[]> {
|
|
813
|
+
public async alignCenter(config: MNode | MNode[], options?: { doNotSelect?: boolean }): Promise<MNode | MNode[]> {
|
|
814
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
815
|
+
|
|
738
816
|
const nodes = Array.isArray(config) ? config : [config];
|
|
739
817
|
const stage = this.get('stage');
|
|
740
818
|
|
|
@@ -742,10 +820,12 @@ class Editor extends BaseService {
|
|
|
742
820
|
|
|
743
821
|
const newNode = await this.update(newNodes);
|
|
744
822
|
|
|
745
|
-
if (
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
823
|
+
if (!doNotSelect) {
|
|
824
|
+
if (newNodes.length > 1) {
|
|
825
|
+
await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
826
|
+
} else {
|
|
827
|
+
await stage?.select(newNodes[0].id);
|
|
828
|
+
}
|
|
749
829
|
}
|
|
750
830
|
|
|
751
831
|
return newNode;
|
|
@@ -808,8 +888,16 @@ class Editor extends BaseService {
|
|
|
808
888
|
* 移动到指定容器中
|
|
809
889
|
* @param config 需要移动的节点
|
|
810
890
|
* @param targetId 容器ID
|
|
891
|
+
* @param options 可选配置
|
|
892
|
+
* @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
|
|
811
893
|
*/
|
|
812
|
-
public async moveToContainer(
|
|
894
|
+
public async moveToContainer(
|
|
895
|
+
config: MNode,
|
|
896
|
+
targetId: Id,
|
|
897
|
+
options?: { doNotSelect?: boolean },
|
|
898
|
+
): Promise<MNode | undefined> {
|
|
899
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
900
|
+
|
|
813
901
|
this.captureSelectionBeforeOp();
|
|
814
902
|
|
|
815
903
|
const root = this.get('root');
|
|
@@ -837,7 +925,9 @@ class Editor extends BaseService {
|
|
|
837
925
|
|
|
838
926
|
target.items.push(newConfig);
|
|
839
927
|
|
|
840
|
-
|
|
928
|
+
if (!doNotSelect) {
|
|
929
|
+
await stage.select(targetId);
|
|
930
|
+
}
|
|
841
931
|
|
|
842
932
|
const targetParent = this.getParentById(target.id);
|
|
843
933
|
await stage.update({
|
|
@@ -846,8 +936,10 @@ class Editor extends BaseService {
|
|
|
846
936
|
root: cloneDeep(root),
|
|
847
937
|
});
|
|
848
938
|
|
|
849
|
-
|
|
850
|
-
|
|
939
|
+
if (!doNotSelect) {
|
|
940
|
+
await this.select(newConfig);
|
|
941
|
+
stage.select(newConfig.id);
|
|
942
|
+
}
|
|
851
943
|
|
|
852
944
|
this.addModifiedNodeId(target.id);
|
|
853
945
|
this.addModifiedNodeId(parent.id);
|
package/types/index.d.ts
CHANGED
|
@@ -405,21 +405,29 @@ declare class Editor extends export_default {
|
|
|
405
405
|
* 向指点容器添加组件节点
|
|
406
406
|
* @param addConfig 将要添加的组件节点配置
|
|
407
407
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
408
|
+
* @param options 可选配置
|
|
409
|
+
* @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
|
|
408
410
|
* @returns 添加后的节点
|
|
409
411
|
*/
|
|
410
|
-
add(addNode: AddMNode | MNode[], parent?: MContainer | null
|
|
411
|
-
|
|
412
|
+
add(addNode: AddMNode | MNode[], parent?: MContainer | null, options?: {
|
|
413
|
+
doNotSelect?: boolean;
|
|
414
|
+
}): Promise<MNode | MNode[]>;
|
|
415
|
+
doRemove(node: MNode, options?: {
|
|
416
|
+
doNotSelect?: boolean;
|
|
417
|
+
}): Promise<void>;
|
|
412
418
|
/**
|
|
413
419
|
* 删除组件
|
|
414
|
-
* @param {Object} node
|
|
420
|
+
* @param {Object} node 要删除的节点或节点集合
|
|
421
|
+
* @param options 可选配置
|
|
422
|
+
* @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
|
|
415
423
|
*/
|
|
416
|
-
remove(nodeOrNodeList: MNode | MNode[]
|
|
424
|
+
remove(nodeOrNodeList: MNode | MNode[], options?: {
|
|
425
|
+
doNotSelect?: boolean;
|
|
426
|
+
}): Promise<void>;
|
|
417
427
|
doUpdate(config: MNode, {
|
|
418
|
-
changeRecords
|
|
419
|
-
selectedAfterUpdate
|
|
428
|
+
changeRecords
|
|
420
429
|
}?: {
|
|
421
430
|
changeRecords?: ChangeRecord[];
|
|
422
|
-
selectedAfterUpdate?: boolean;
|
|
423
431
|
}): Promise<{
|
|
424
432
|
newNode: MNode;
|
|
425
433
|
oldNode: MNode;
|
|
@@ -433,15 +441,18 @@ declare class Editor extends export_default {
|
|
|
433
441
|
*/
|
|
434
442
|
update(config: MNode | MNode[], data?: {
|
|
435
443
|
changeRecords?: ChangeRecord[];
|
|
436
|
-
selectedAfterUpdate?: boolean;
|
|
437
444
|
}): Promise<MNode | MNode[]>;
|
|
438
445
|
/**
|
|
439
446
|
* 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
|
|
440
447
|
* @param id1 组件ID
|
|
441
448
|
* @param id2 组件ID
|
|
449
|
+
* @param options 可选配置
|
|
450
|
+
* @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
|
|
442
451
|
* @returns void
|
|
443
452
|
*/
|
|
444
|
-
sort(id1: Id, id2: Id
|
|
453
|
+
sort(id1: Id, id2: Id, options?: {
|
|
454
|
+
doNotSelect?: boolean;
|
|
455
|
+
}): Promise<void>;
|
|
445
456
|
/**
|
|
446
457
|
* 将组件节点配置存储到localStorage中
|
|
447
458
|
* @param config 组件节点配置
|
|
@@ -457,17 +468,26 @@ declare class Editor extends export_default {
|
|
|
457
468
|
/**
|
|
458
469
|
* 从localStorage中获取节点,然后添加到当前容器中
|
|
459
470
|
* @param position 粘贴的坐标
|
|
471
|
+
* @param collectorOptions 可选的依赖收集器配置
|
|
472
|
+
* @param options 可选配置
|
|
473
|
+
* @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
|
|
460
474
|
* @returns 添加后的组件节点配置
|
|
461
475
|
*/
|
|
462
|
-
paste(position?: PastePosition, collectorOptions?: TargetOptions
|
|
476
|
+
paste(position?: PastePosition, collectorOptions?: TargetOptions, options?: {
|
|
477
|
+
doNotSelect?: boolean;
|
|
478
|
+
}): Promise<MNode | MNode[] | void>;
|
|
463
479
|
doPaste(config: MNode[], position?: PastePosition): Promise<MNode[]>;
|
|
464
480
|
doAlignCenter(config: MNode): Promise<MNode>;
|
|
465
481
|
/**
|
|
466
482
|
* 将指点节点设置居中
|
|
467
483
|
* @param config 组件节点配置
|
|
484
|
+
* @param options 可选配置
|
|
485
|
+
* @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
|
|
468
486
|
* @returns 当前组件节点配置
|
|
469
487
|
*/
|
|
470
|
-
alignCenter(config: MNode | MNode[]
|
|
488
|
+
alignCenter(config: MNode | MNode[], options?: {
|
|
489
|
+
doNotSelect?: boolean;
|
|
490
|
+
}): Promise<MNode | MNode[]>;
|
|
471
491
|
/**
|
|
472
492
|
* 移动当前选中节点位置
|
|
473
493
|
* @param offset 偏移量
|
|
@@ -477,8 +497,12 @@ declare class Editor extends export_default {
|
|
|
477
497
|
* 移动到指定容器中
|
|
478
498
|
* @param config 需要移动的节点
|
|
479
499
|
* @param targetId 容器ID
|
|
500
|
+
* @param options 可选配置
|
|
501
|
+
* @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
|
|
480
502
|
*/
|
|
481
|
-
moveToContainer(config: MNode, targetId: Id
|
|
503
|
+
moveToContainer(config: MNode, targetId: Id, options?: {
|
|
504
|
+
doNotSelect?: boolean;
|
|
505
|
+
}): Promise<MNode | undefined>;
|
|
482
506
|
dragTo(config: MNode | MNode[], targetParent: MContainer, targetIndex: number): Promise<void>;
|
|
483
507
|
/**
|
|
484
508
|
* 撤销当前操作
|