@tmagic/editor 1.3.5 → 1.3.7
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 +5432 -0
- package/dist/style.css +88 -62
- package/dist/tmagic-editor.js +2448 -2016
- package/dist/tmagic-editor.js.map +1 -1
- package/dist/tmagic-editor.umd.cjs +2453 -2019
- package/dist/tmagic-editor.umd.cjs.map +1 -1
- package/package.json +23 -23
- package/src/Editor.vue +15 -7
- package/src/components/CodeBlockEditor.vue +2 -2
- package/src/components/ContentMenu.vue +5 -5
- package/src/components/FloatingBox.vue +117 -0
- package/src/components/ScrollBar.vue +2 -2
- package/src/components/ScrollViewer.vue +2 -2
- package/src/components/SplitView.vue +2 -2
- package/src/components/Tree.vue +5 -0
- package/src/components/TreeNode.vue +10 -4
- package/src/editorProps.ts +20 -3
- package/src/fields/PageFragmentSelect.vue +55 -0
- package/src/hooks/use-filter.ts +55 -0
- package/src/hooks/use-getso.ts +2 -2
- package/src/hooks/use-node-status.ts +48 -0
- package/src/hooks/use-stage.ts +19 -1
- package/src/index.ts +3 -0
- package/src/initService.ts +43 -17
- package/src/layouts/AddPageBox.vue +16 -4
- package/src/layouts/CodeEditor.vue +2 -2
- package/src/layouts/Framework.vue +17 -3
- package/src/layouts/PropsPanel.vue +2 -2
- package/src/layouts/page-bar/AddButton.vue +48 -0
- package/src/layouts/page-bar/PageBar.vue +158 -0
- package/src/layouts/{workspace → page-bar}/PageBarScrollContainer.vue +61 -35
- package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
- package/src/layouts/sidebar/Sidebar.vue +9 -2
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +55 -65
- package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +2 -1
- package/src/layouts/sidebar/data-source/DataSourceList.vue +63 -59
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +1 -1
- package/src/layouts/sidebar/layer/LayerMenu.vue +39 -27
- package/src/layouts/sidebar/layer/LayerPanel.vue +31 -8
- package/src/layouts/sidebar/layer/use-click.ts +5 -3
- package/src/layouts/sidebar/layer/use-keybinding.ts +8 -8
- package/src/layouts/sidebar/layer/use-node-status.ts +10 -13
- package/src/layouts/workspace/Workspace.vue +6 -7
- package/src/layouts/workspace/viewer/NodeListMenu.vue +68 -129
- package/src/layouts/workspace/viewer/Stage.vue +14 -6
- package/src/layouts/workspace/viewer/ViewerMenu.vue +94 -86
- package/src/services/BaseService.ts +63 -26
- package/src/services/codeBlock.ts +7 -1
- package/src/services/dep.ts +12 -8
- package/src/services/editor.ts +131 -64
- package/src/services/history.ts +6 -2
- package/src/services/keybinding.ts +48 -13
- package/src/services/props.ts +70 -12
- package/src/services/storage.ts +23 -13
- package/src/services/ui.ts +4 -1
- package/src/theme/code-block.scss +0 -16
- package/src/theme/floating-box.scss +30 -0
- package/src/theme/layer-panel.scss +19 -0
- package/src/theme/page-bar.scss +18 -1
- package/src/theme/stage.scss +24 -0
- package/src/theme/theme.scss +1 -1
- package/src/theme/tree.scss +12 -1
- package/src/type.ts +28 -10
- package/src/utils/compose.ts +25 -6
- package/src/utils/content-menu.ts +6 -7
- package/src/utils/editor.ts +34 -18
- package/src/utils/operator.ts +5 -6
- package/types/components/CodeBlockEditor.vue.d.ts +6 -2
- package/types/components/CodeParams.vue.d.ts +3 -1
- package/types/components/ContentMenu.vue.d.ts +13 -5
- package/types/components/FloatingBox.vue.d.ts +78 -0
- package/types/components/Resizer.vue.d.ts +6 -1
- package/types/components/ScrollBar.vue.d.ts +3 -1
- package/types/components/ScrollViewer.vue.d.ts +3 -3
- package/types/components/SearchInput.vue.d.ts +3 -1
- package/types/components/SplitView.vue.d.ts +8 -4
- package/types/components/ToolButton.vue.d.ts +3 -3
- package/types/components/Tree.vue.d.ts +27 -8
- package/types/components/TreeNode.vue.d.ts +24 -7
- package/types/editorProps.d.ts +16 -1
- package/types/fields/Code.vue.d.ts +6 -2
- package/types/fields/CodeLink.vue.d.ts +5 -3
- package/types/fields/CodeSelect.vue.d.ts +3 -1
- package/types/fields/CodeSelectCol.vue.d.ts +3 -1
- package/types/fields/DataSourceFieldSelect.vue.d.ts +3 -1
- package/types/fields/DataSourceFields.vue.d.ts +5 -3
- package/types/fields/DataSourceInput.vue.d.ts +8 -4
- package/types/fields/DataSourceMethodSelect.vue.d.ts +3 -1
- package/types/fields/DataSourceMethods.vue.d.ts +5 -3
- package/types/fields/DataSourceMocks.vue.d.ts +5 -3
- package/types/fields/DataSourceSelect.vue.d.ts +5 -3
- package/types/fields/EventSelect.vue.d.ts +3 -1
- package/types/fields/KeyValue.vue.d.ts +2 -2
- package/types/fields/PageFragmentSelect.vue.d.ts +31 -0
- package/types/fields/UISelect.vue.d.ts +3 -1
- package/types/hooks/use-code-block-edit.d.ts +14 -5
- package/types/hooks/use-data-source-method.d.ts +14 -5
- package/types/hooks/use-filter.d.ts +7 -0
- package/types/hooks/use-node-status.d.ts +6 -0
- package/types/index.d.ts +1 -0
- package/types/layouts/AddPageBox.vue.d.ts +14 -1
- package/types/layouts/CodeEditor.vue.d.ts +4 -1
- package/types/layouts/Framework.vue.d.ts +14 -1
- package/types/layouts/PropsPanel.vue.d.ts +19 -13
- package/types/layouts/{workspace/viewer/NodeListMenuTitle.vue.d.ts → page-bar/AddButton.vue.d.ts} +3 -2
- package/types/layouts/page-bar/PageBar.vue.d.ts +28 -0
- package/types/layouts/page-bar/PageBarScrollContainer.vue.d.ts +24 -0
- package/types/layouts/page-bar/SwitchTypeButton.vue.d.ts +20 -0
- package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +1 -1
- package/types/layouts/sidebar/Sidebar.vue.d.ts +7 -5
- package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +9 -3
- package/types/layouts/sidebar/code-block/CodeBlockListPanel.vue.d.ts +1 -1
- package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +3 -1
- package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +8 -2
- package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +1 -1
- package/types/layouts/sidebar/layer/LayerMenu.vue.d.ts +26 -3
- package/types/layouts/sidebar/layer/LayerPanel.vue.d.ts +3 -1
- package/types/layouts/sidebar/layer/use-click.d.ts +37 -6
- package/types/layouts/sidebar/layer/use-keybinding.d.ts +1 -1
- package/types/layouts/sidebar/layer/use-node-status.d.ts +3 -4
- package/types/layouts/workspace/Workspace.vue.d.ts +3 -1
- package/types/layouts/workspace/viewer/NodeListMenu.vue.d.ts +1 -14
- package/types/layouts/workspace/viewer/Stage.vue.d.ts +2 -0
- package/types/layouts/workspace/viewer/ViewerMenu.vue.d.ts +9 -1
- package/types/services/BaseService.d.ts +4 -1
- package/types/services/dataSource.d.ts +1 -0
- package/types/services/dep.d.ts +6 -5
- package/types/services/editor.d.ts +12 -5
- package/types/services/history.d.ts +3 -2
- package/types/services/keybinding.d.ts +21 -1
- package/types/services/props.d.ts +25 -1
- package/types/services/storage.d.ts +7 -7
- package/types/type.d.ts +32 -17
- package/types/utils/compose.d.ts +1 -1
- package/types/utils/editor.d.ts +14 -8
- package/src/layouts/sidebar/layer/use-filter.ts +0 -59
- package/src/layouts/workspace/PageBar.vue +0 -87
- package/src/layouts/workspace/viewer/NodeListMenuTitle.vue +0 -68
- package/src/theme/dep-list.scss +0 -59
- package/types/layouts/sidebar/layer/use-filter.d.ts +0 -7
- package/types/layouts/workspace/PageBar.vue.d.ts +0 -15
- package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +0 -9
package/src/services/editor.ts
CHANGED
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { reactive, toRaw } from 'vue';
|
|
20
|
-
import { cloneDeep, isObject, mergeWith, uniq } from 'lodash-es';
|
|
20
|
+
import { cloneDeep, get, isObject, mergeWith, uniq } from 'lodash-es';
|
|
21
21
|
|
|
22
|
-
import
|
|
22
|
+
import { DepTargetType } from '@tmagic/dep';
|
|
23
|
+
import type { Id, MApp, MComponent, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
|
|
23
24
|
import { NodeType } from '@tmagic/schema';
|
|
24
|
-
import
|
|
25
|
-
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
|
25
|
+
import { getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
|
|
26
26
|
|
|
27
|
+
import depService from '@editor/services/dep';
|
|
27
28
|
import historyService from '@editor/services/history';
|
|
28
29
|
import storageService, { Protocol } from '@editor/services/storage';
|
|
29
30
|
import type { AddMNode, EditorNodeInfo, PastePosition, StepValue, StoreState, StoreStateKey } from '@editor/type';
|
|
@@ -35,8 +36,10 @@ import {
|
|
|
35
36
|
fixNodePosition,
|
|
36
37
|
getInitPositionStyle,
|
|
37
38
|
getNodeIndex,
|
|
39
|
+
getPageFragmentList,
|
|
40
|
+
getPageList,
|
|
38
41
|
isFixed,
|
|
39
|
-
|
|
42
|
+
setChildrenLayout,
|
|
40
43
|
setLayout,
|
|
41
44
|
} from '@editor/utils/editor';
|
|
42
45
|
import { beforePaste, getAddParent } from '@editor/utils/operator';
|
|
@@ -52,36 +55,39 @@ class Editor extends BaseService {
|
|
|
52
55
|
node: null,
|
|
53
56
|
nodes: [],
|
|
54
57
|
stage: null,
|
|
58
|
+
stageLoading: true,
|
|
55
59
|
highlightNode: null,
|
|
56
60
|
modifiedNodeIds: new Map(),
|
|
57
61
|
pageLength: 0,
|
|
62
|
+
pageFragmentLength: 0,
|
|
63
|
+
disabledMultiSelect: false,
|
|
58
64
|
});
|
|
59
65
|
private isHistoryStateChange = false;
|
|
60
66
|
|
|
61
67
|
constructor() {
|
|
62
68
|
super(
|
|
63
69
|
[
|
|
64
|
-
'getLayout',
|
|
65
|
-
'select',
|
|
66
|
-
'doAdd',
|
|
67
|
-
'add',
|
|
68
|
-
'doRemove',
|
|
69
|
-
'remove',
|
|
70
|
-
'doUpdate',
|
|
71
|
-
'update',
|
|
72
|
-
'sort',
|
|
73
|
-
'copy',
|
|
74
|
-
'paste',
|
|
75
|
-
'doPaste',
|
|
76
|
-
'doAlignCenter',
|
|
77
|
-
'alignCenter',
|
|
78
|
-
'moveLayer',
|
|
79
|
-
'moveToContainer',
|
|
80
|
-
'move',
|
|
81
|
-
'undo',
|
|
82
|
-
'redo',
|
|
83
|
-
'highlight',
|
|
84
|
-
'dragTo',
|
|
70
|
+
{ name: 'getLayout', isAsync: true },
|
|
71
|
+
{ name: 'select', isAsync: true },
|
|
72
|
+
{ name: 'doAdd', isAsync: true },
|
|
73
|
+
{ name: 'add', isAsync: true },
|
|
74
|
+
{ name: 'doRemove', isAsync: true },
|
|
75
|
+
{ name: 'remove', isAsync: true },
|
|
76
|
+
{ name: 'doUpdate', isAsync: true },
|
|
77
|
+
{ name: 'update', isAsync: true },
|
|
78
|
+
{ name: 'sort', isAsync: true },
|
|
79
|
+
{ name: 'copy', isAsync: true },
|
|
80
|
+
{ name: 'paste', isAsync: true },
|
|
81
|
+
{ name: 'doPaste', isAsync: true },
|
|
82
|
+
{ name: 'doAlignCenter', isAsync: true },
|
|
83
|
+
{ name: 'alignCenter', isAsync: true },
|
|
84
|
+
{ name: 'moveLayer', isAsync: true },
|
|
85
|
+
{ name: 'moveToContainer', isAsync: true },
|
|
86
|
+
{ name: 'move', isAsync: true },
|
|
87
|
+
{ name: 'undo', isAsync: true },
|
|
88
|
+
{ name: 'redo', isAsync: true },
|
|
89
|
+
{ name: 'highlight', isAsync: true },
|
|
90
|
+
{ name: 'dragTo', isAsync: true },
|
|
85
91
|
],
|
|
86
92
|
// 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用
|
|
87
93
|
['select', 'update', 'moveLayer'],
|
|
@@ -90,7 +96,7 @@ class Editor extends BaseService {
|
|
|
90
96
|
|
|
91
97
|
/**
|
|
92
98
|
* 设置当前指点节点配置
|
|
93
|
-
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength'
|
|
99
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength
|
|
94
100
|
* @param value MNode
|
|
95
101
|
*/
|
|
96
102
|
public set<K extends StoreStateKey, T extends StoreState[K]>(name: K, value: T) {
|
|
@@ -107,10 +113,15 @@ class Editor extends BaseService {
|
|
|
107
113
|
throw new Error('root 不能为数组');
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
if (value && isObject(value)
|
|
111
|
-
|
|
116
|
+
if (value && isObject(value)) {
|
|
117
|
+
const app = value as MApp;
|
|
118
|
+
this.state.pageLength = getPageList(app).length || 0;
|
|
119
|
+
this.state.pageFragmentLength = getPageFragmentList(app).length || 0;
|
|
120
|
+
this.state.stageLoading = this.state.pageLength !== 0;
|
|
112
121
|
} else {
|
|
113
122
|
this.state.pageLength = 0;
|
|
123
|
+
this.state.pageFragmentLength = 0;
|
|
124
|
+
this.state.stageLoading = false;
|
|
114
125
|
}
|
|
115
126
|
|
|
116
127
|
this.emit('root-change', value, preValue);
|
|
@@ -119,7 +130,7 @@ class Editor extends BaseService {
|
|
|
119
130
|
|
|
120
131
|
/**
|
|
121
132
|
* 获取当前指点节点配置
|
|
122
|
-
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength'
|
|
133
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength'
|
|
123
134
|
* @returns MNode
|
|
124
135
|
*/
|
|
125
136
|
public get<K extends StoreStateKey>(name: K): StoreState[K] {
|
|
@@ -161,8 +172,8 @@ class Editor extends BaseService {
|
|
|
161
172
|
info.parent = path[path.length - 2] as MContainer;
|
|
162
173
|
|
|
163
174
|
path.forEach((item) => {
|
|
164
|
-
if (item
|
|
165
|
-
info.page = item as MPage;
|
|
175
|
+
if (isPage(item) || isPageFragment(item)) {
|
|
176
|
+
info.page = item as MPage | MPageFragment;
|
|
166
177
|
return;
|
|
167
178
|
}
|
|
168
179
|
});
|
|
@@ -310,6 +321,17 @@ class Editor extends BaseService {
|
|
|
310
321
|
this.set('nodes', nodes);
|
|
311
322
|
}
|
|
312
323
|
|
|
324
|
+
public selectRoot() {
|
|
325
|
+
const root = this.get('root');
|
|
326
|
+
if (!root) return;
|
|
327
|
+
|
|
328
|
+
this.set('nodes', [root]);
|
|
329
|
+
this.set('parent', null);
|
|
330
|
+
this.set('page', null);
|
|
331
|
+
this.set('stage', null);
|
|
332
|
+
this.set('highlightNode', null);
|
|
333
|
+
}
|
|
334
|
+
|
|
313
335
|
public async doAdd(node: MNode, parent: MContainer): Promise<MNode> {
|
|
314
336
|
const root = this.get('root');
|
|
315
337
|
|
|
@@ -320,11 +342,11 @@ class Editor extends BaseService {
|
|
|
320
342
|
|
|
321
343
|
if (!curNode) throw new Error('当前选中节点为空');
|
|
322
344
|
|
|
323
|
-
if ((parent.type === NodeType.ROOT || curNode?.type === NodeType.ROOT) && node
|
|
345
|
+
if ((parent.type === NodeType.ROOT || curNode?.type === NodeType.ROOT) && !(isPage(node) || isPageFragment(node))) {
|
|
324
346
|
throw new Error('app下不能添加组件');
|
|
325
347
|
}
|
|
326
348
|
|
|
327
|
-
if (parent.id !== curNode.id && node
|
|
349
|
+
if (parent.id !== curNode.id && !(isPage(node) || isPageFragment(node))) {
|
|
328
350
|
const index = parent.items.indexOf(curNode);
|
|
329
351
|
parent.items?.splice(index + 1, 0, node);
|
|
330
352
|
} else {
|
|
@@ -378,7 +400,7 @@ class Editor extends BaseService {
|
|
|
378
400
|
const newNodes = await Promise.all(
|
|
379
401
|
addNodes.map((node) => {
|
|
380
402
|
const root = this.get('root');
|
|
381
|
-
if (isPage(node) && root) {
|
|
403
|
+
if ((isPage(node) || isPageFragment(node)) && root) {
|
|
382
404
|
return this.doAdd(node, root);
|
|
383
405
|
}
|
|
384
406
|
const parentNode = parent && typeof parent !== 'function' ? parent : getAddParent(node);
|
|
@@ -397,13 +419,15 @@ class Editor extends BaseService {
|
|
|
397
419
|
|
|
398
420
|
if (isPage(newNodes[0])) {
|
|
399
421
|
this.state.pageLength += 1;
|
|
422
|
+
} else if (isPageFragment(newNodes[0])) {
|
|
423
|
+
this.state.pageFragmentLength += 1;
|
|
400
424
|
} else {
|
|
401
425
|
// 新增页面,这个时候页面还有渲染出来,此时select会出错,在runtime-ready的时候回去select
|
|
402
426
|
stage?.select(newNodes[0].id);
|
|
403
427
|
}
|
|
404
428
|
}
|
|
405
429
|
|
|
406
|
-
if (!isPage(newNodes[0])) {
|
|
430
|
+
if (!(isPage(newNodes[0]) || isPageFragment(newNodes[0]))) {
|
|
407
431
|
this.pushHistoryState();
|
|
408
432
|
}
|
|
409
433
|
|
|
@@ -416,7 +440,7 @@ class Editor extends BaseService {
|
|
|
416
440
|
const root = this.get('root');
|
|
417
441
|
if (!root) throw new Error('root不能为空');
|
|
418
442
|
|
|
419
|
-
const { parent, node: curNode } = this.getNodeInfo(node.id);
|
|
443
|
+
const { parent, node: curNode } = this.getNodeInfo(node.id, false);
|
|
420
444
|
|
|
421
445
|
if (!parent || !curNode) throw new Error('找不要删除的节点');
|
|
422
446
|
|
|
@@ -428,29 +452,38 @@ class Editor extends BaseService {
|
|
|
428
452
|
const stage = this.get('stage');
|
|
429
453
|
stage?.remove({ id: node.id, parentId: parent.id, root: cloneDeep(root) });
|
|
430
454
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
await this.select(root.items[0]);
|
|
436
|
-
stage?.select(root.items[0].id);
|
|
455
|
+
const selectDefault = async (pages: MNode[]) => {
|
|
456
|
+
if (pages[0]) {
|
|
457
|
+
await this.select(pages[0]);
|
|
458
|
+
stage?.select(pages[0].id);
|
|
437
459
|
} else {
|
|
438
|
-
this.
|
|
439
|
-
this.set('parent', null);
|
|
440
|
-
this.set('page', null);
|
|
441
|
-
this.set('stage', null);
|
|
442
|
-
this.set('highlightNode', null);
|
|
443
|
-
this.resetModifiedNodeId();
|
|
444
|
-
historyService.reset();
|
|
460
|
+
this.selectRoot();
|
|
445
461
|
|
|
446
|
-
|
|
462
|
+
historyService.resetPage();
|
|
447
463
|
}
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
const rootItems = root.items || [];
|
|
467
|
+
|
|
468
|
+
if (isPage(node)) {
|
|
469
|
+
this.state.pageLength -= 1;
|
|
470
|
+
|
|
471
|
+
await selectDefault(getPageList(root));
|
|
472
|
+
} else if (isPageFragment(node)) {
|
|
473
|
+
this.state.pageFragmentLength -= 1;
|
|
474
|
+
|
|
475
|
+
await selectDefault(getPageFragmentList(root));
|
|
448
476
|
} else {
|
|
449
477
|
await this.select(parent);
|
|
450
478
|
stage?.select(parent.id);
|
|
479
|
+
|
|
480
|
+
this.addModifiedNodeId(parent.id);
|
|
451
481
|
}
|
|
452
482
|
|
|
453
|
-
|
|
483
|
+
if (!rootItems.length) {
|
|
484
|
+
this.resetModifiedNodeId();
|
|
485
|
+
historyService.reset();
|
|
486
|
+
}
|
|
454
487
|
}
|
|
455
488
|
|
|
456
489
|
/**
|
|
@@ -462,7 +495,7 @@ class Editor extends BaseService {
|
|
|
462
495
|
|
|
463
496
|
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
464
497
|
|
|
465
|
-
if (!isPage(nodes[0])) {
|
|
498
|
+
if (!(isPage(nodes[0]) || isPageFragment(nodes[0]))) {
|
|
466
499
|
// 更新历史记录
|
|
467
500
|
this.pushHistoryState();
|
|
468
501
|
}
|
|
@@ -512,7 +545,7 @@ class Editor extends BaseService {
|
|
|
512
545
|
const newLayout = await this.getLayout(newConfig);
|
|
513
546
|
const layout = await this.getLayout(node);
|
|
514
547
|
if (Array.isArray(newConfig.items) && newLayout !== layout) {
|
|
515
|
-
newConfig =
|
|
548
|
+
newConfig = setChildrenLayout(newConfig as MContainer, newLayout);
|
|
516
549
|
}
|
|
517
550
|
|
|
518
551
|
parentNodeItems[index] = newConfig;
|
|
@@ -529,8 +562,8 @@ class Editor extends BaseService {
|
|
|
529
562
|
root: cloneDeep(root),
|
|
530
563
|
});
|
|
531
564
|
|
|
532
|
-
if (newConfig
|
|
533
|
-
this.set('page', newConfig as MPage);
|
|
565
|
+
if (isPage(newConfig) || isPageFragment(newConfig)) {
|
|
566
|
+
this.set('page', newConfig as MPage | MPageFragment);
|
|
534
567
|
}
|
|
535
568
|
|
|
536
569
|
this.addModifiedNodeId(newConfig.id);
|
|
@@ -593,12 +626,47 @@ class Editor extends BaseService {
|
|
|
593
626
|
}
|
|
594
627
|
|
|
595
628
|
/**
|
|
596
|
-
*
|
|
629
|
+
* 将组件节点配置存储到localStorage中
|
|
597
630
|
* @param config 组件节点配置
|
|
598
|
-
* @returns
|
|
631
|
+
* @returns
|
|
632
|
+
*/
|
|
633
|
+
public copy(config: MNode | MNode[]): void {
|
|
634
|
+
storageService.setItem(COPY_STORAGE_KEY, Array.isArray(config) ? config : [config], {
|
|
635
|
+
protocol: Protocol.OBJECT,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* 复制时会带上组件关联的依赖
|
|
641
|
+
* @param config 组件节点配置
|
|
642
|
+
* @returns
|
|
599
643
|
*/
|
|
600
|
-
public
|
|
601
|
-
|
|
644
|
+
public copyWithRelated(config: MNode | MNode[]): void {
|
|
645
|
+
const copyNodes: MNode[] = Array.isArray(config) ? config : [config];
|
|
646
|
+
// 关联的组件也一并复制
|
|
647
|
+
depService.getTarget(DepTargetType.RELATED_COMP_WHEN_COPY, DepTargetType.RELATED_COMP_WHEN_COPY)?.removeDep();
|
|
648
|
+
depService.collect(copyNodes, true, DepTargetType.RELATED_COMP_WHEN_COPY);
|
|
649
|
+
const customTarget = depService.getTarget(
|
|
650
|
+
DepTargetType.RELATED_COMP_WHEN_COPY,
|
|
651
|
+
DepTargetType.RELATED_COMP_WHEN_COPY,
|
|
652
|
+
);
|
|
653
|
+
if (customTarget) {
|
|
654
|
+
Object.keys(customTarget.deps).forEach((nodeId: Id) => {
|
|
655
|
+
const node = this.getNodeById(nodeId);
|
|
656
|
+
if (!node) return;
|
|
657
|
+
customTarget!.deps[nodeId].keys.forEach((key) => {
|
|
658
|
+
const relateNodeId = get(node, key);
|
|
659
|
+
const isExist = copyNodes.find((node) => node.id === relateNodeId);
|
|
660
|
+
if (!isExist) {
|
|
661
|
+
const relateNode = this.getNodeById(relateNodeId);
|
|
662
|
+
if (relateNode) {
|
|
663
|
+
copyNodes.push(relateNode);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
storageService.setItem(COPY_STORAGE_KEY, copyNodes, {
|
|
602
670
|
protocol: Protocol.OBJECT,
|
|
603
671
|
});
|
|
604
672
|
}
|
|
@@ -609,8 +677,7 @@ class Editor extends BaseService {
|
|
|
609
677
|
* @returns 添加后的组件节点配置
|
|
610
678
|
*/
|
|
611
679
|
public async paste(position: PastePosition = {}): Promise<MNode | MNode[] | void> {
|
|
612
|
-
const config: MNode[] =
|
|
613
|
-
|
|
680
|
+
const config: MNode[] = storageService.getItem(COPY_STORAGE_KEY);
|
|
614
681
|
if (!Array.isArray(config)) return;
|
|
615
682
|
|
|
616
683
|
const node = this.get('node');
|
|
@@ -623,13 +690,13 @@ class Editor extends BaseService {
|
|
|
623
690
|
parent = this.get('page');
|
|
624
691
|
}
|
|
625
692
|
}
|
|
626
|
-
|
|
627
693
|
const pasteConfigs = await this.doPaste(config, position);
|
|
628
|
-
|
|
694
|
+
propsService.replaceRelateId(config, pasteConfigs);
|
|
629
695
|
return this.add(pasteConfigs, parent);
|
|
630
696
|
}
|
|
631
697
|
|
|
632
698
|
public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
|
|
699
|
+
propsService.clearRelateId();
|
|
633
700
|
const pasteConfigs = await beforePaste(position, cloneDeep(config));
|
|
634
701
|
return pasteConfigs;
|
|
635
702
|
}
|
package/src/services/history.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import { reactive } from 'vue';
|
|
20
20
|
|
|
21
|
-
import type { MPage } from '@tmagic/schema';
|
|
21
|
+
import type { MPage, MPageFragment } from '@tmagic/schema';
|
|
22
22
|
|
|
23
23
|
import type { HistoryState, StepValue } from '@editor/type';
|
|
24
24
|
import { UndoRedo } from '@editor/utils/undo-redo';
|
|
@@ -41,12 +41,16 @@ class History extends BaseService {
|
|
|
41
41
|
|
|
42
42
|
public reset() {
|
|
43
43
|
this.state.pageSteps = {};
|
|
44
|
+
this.resetPage();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public resetPage() {
|
|
44
48
|
this.state.pageId = undefined;
|
|
45
49
|
this.state.canRedo = false;
|
|
46
50
|
this.state.canUndo = false;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
public changePage(page: MPage): void {
|
|
53
|
+
public changePage(page: MPage | MPageFragment): void {
|
|
50
54
|
if (!page) return;
|
|
51
55
|
|
|
52
56
|
this.state.pageId = page.id;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import KeyController, { KeyControllerEvent } from 'keycon';
|
|
2
2
|
|
|
3
|
-
import { isPage } from '@tmagic/utils';
|
|
3
|
+
import { isPage, isPageFragment } from '@tmagic/utils';
|
|
4
4
|
|
|
5
5
|
import { KeyBindingCacheItem, KeyBindingCommand, KeyBindingItem } from '@editor/type';
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ class Keybinding extends BaseService {
|
|
|
19
19
|
[KeyBindingCommand.DELETE_NODE]: () => {
|
|
20
20
|
const nodes = editorService.get('nodes');
|
|
21
21
|
|
|
22
|
-
if (!nodes || isPage(nodes[0])) return;
|
|
22
|
+
if (!nodes || isPage(nodes[0]) || isPageFragment(nodes[0])) return;
|
|
23
23
|
editorService.remove(nodes);
|
|
24
24
|
},
|
|
25
25
|
[KeyBindingCommand.COPY_NODE]: () => {
|
|
@@ -29,7 +29,7 @@ class Keybinding extends BaseService {
|
|
|
29
29
|
[KeyBindingCommand.CUT_NODE]: () => {
|
|
30
30
|
const nodes = editorService.get('nodes');
|
|
31
31
|
|
|
32
|
-
if (!nodes || isPage(nodes[0])) return;
|
|
32
|
+
if (!nodes || isPage(nodes[0]) || isPageFragment(nodes[0])) return;
|
|
33
33
|
editorService.copy(nodes);
|
|
34
34
|
editorService.remove(nodes);
|
|
35
35
|
},
|
|
@@ -84,15 +84,29 @@ class Keybinding extends BaseService {
|
|
|
84
84
|
},
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
public
|
|
87
|
+
public registerCommand(command: string, handler: (e: KeyboardEvent) => void | Promise<void>) {
|
|
88
88
|
this.commands[command] = handler;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
/**
|
|
92
|
+
* @deprecated
|
|
93
|
+
*/
|
|
94
|
+
public registeCommand(command: string, handler: (e: KeyboardEvent) => void | Promise<void>) {
|
|
95
|
+
this.registerCommand(command, handler);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public unregisterCommand(command: string) {
|
|
92
99
|
delete this.commands[command];
|
|
93
100
|
}
|
|
94
101
|
|
|
95
|
-
|
|
102
|
+
/**
|
|
103
|
+
* @deprecated
|
|
104
|
+
*/
|
|
105
|
+
public unregisteCommand(command: string) {
|
|
106
|
+
this.unregisterCommand(command);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public registerEl(name: string, el?: HTMLElement) {
|
|
96
110
|
if (name !== 'global' && !el) {
|
|
97
111
|
throw new Error('只有name为global可以不传el');
|
|
98
112
|
}
|
|
@@ -102,20 +116,34 @@ class Keybinding extends BaseService {
|
|
|
102
116
|
this.bind(name);
|
|
103
117
|
}
|
|
104
118
|
|
|
105
|
-
|
|
119
|
+
/**
|
|
120
|
+
* @deprecated
|
|
121
|
+
*/
|
|
122
|
+
public registeEl(name: string, el?: HTMLElement) {
|
|
123
|
+
this.registerEl(name, el);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public unregisterEl(name: string) {
|
|
106
127
|
this.controllers.get(name)?.destroy();
|
|
107
128
|
this.controllers.delete(name);
|
|
108
129
|
this.bindingList.forEach((item) => {
|
|
109
|
-
item.
|
|
130
|
+
item.bound = false;
|
|
110
131
|
});
|
|
111
132
|
}
|
|
112
133
|
|
|
113
|
-
|
|
134
|
+
/**
|
|
135
|
+
* @deprecated
|
|
136
|
+
*/
|
|
137
|
+
public unregisteEl(name: string) {
|
|
138
|
+
this.unregisterEl(name);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public register(maps: KeyBindingItem[]) {
|
|
114
142
|
for (const keybindingItem of maps) {
|
|
115
143
|
const { command, keybinding, when } = keybindingItem;
|
|
116
144
|
|
|
117
145
|
for (const [type = '', eventType = 'keydown'] of when) {
|
|
118
|
-
const cacheItem: KeyBindingCacheItem = { type, command, keybinding, eventType,
|
|
146
|
+
const cacheItem: KeyBindingCacheItem = { type, command, keybinding, eventType, bound: false };
|
|
119
147
|
|
|
120
148
|
this.bindingList.push(cacheItem);
|
|
121
149
|
}
|
|
@@ -124,6 +152,13 @@ class Keybinding extends BaseService {
|
|
|
124
152
|
this.bind();
|
|
125
153
|
}
|
|
126
154
|
|
|
155
|
+
/**
|
|
156
|
+
* @deprecated
|
|
157
|
+
*/
|
|
158
|
+
public registe(map: KeyBindingItem[]) {
|
|
159
|
+
this.register(map);
|
|
160
|
+
}
|
|
161
|
+
|
|
127
162
|
public reset() {
|
|
128
163
|
this.controllers.forEach((keycon) => {
|
|
129
164
|
keycon.destroy();
|
|
@@ -138,13 +173,13 @@ class Keybinding extends BaseService {
|
|
|
138
173
|
|
|
139
174
|
private bind(name?: string) {
|
|
140
175
|
for (const item of this.bindingList) {
|
|
141
|
-
const { type, eventType, command, keybinding,
|
|
176
|
+
const { type, eventType, command, keybinding, bound } = item;
|
|
142
177
|
|
|
143
178
|
if (name && name !== type) {
|
|
144
179
|
continue;
|
|
145
180
|
}
|
|
146
181
|
|
|
147
|
-
if (
|
|
182
|
+
if (bound) {
|
|
148
183
|
continue;
|
|
149
184
|
}
|
|
150
185
|
|
|
@@ -166,7 +201,7 @@ class Keybinding extends BaseService {
|
|
|
166
201
|
}
|
|
167
202
|
});
|
|
168
203
|
|
|
169
|
-
item.
|
|
204
|
+
item.bound = true;
|
|
170
205
|
}
|
|
171
206
|
}
|
|
172
207
|
|
package/src/services/props.ts
CHANGED
|
@@ -17,12 +17,15 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { reactive } from 'vue';
|
|
20
|
-
import { cloneDeep, mergeWith } from 'lodash-es';
|
|
20
|
+
import { cloneDeep, get, mergeWith, set } from 'lodash-es';
|
|
21
21
|
|
|
22
|
+
import { DepTargetType } from '@tmagic/dep';
|
|
22
23
|
import type { FormConfig } from '@tmagic/form';
|
|
23
|
-
import type { MComponent, MNode } from '@tmagic/schema';
|
|
24
|
+
import type { Id, MComponent, MNode } from '@tmagic/schema';
|
|
24
25
|
import { guid, toLine } from '@tmagic/utils';
|
|
25
26
|
|
|
27
|
+
import depService from '@editor/services/dep';
|
|
28
|
+
import editorService from '@editor/services/editor';
|
|
26
29
|
import type { PropsState } from '@editor/type';
|
|
27
30
|
import { fillConfig } from '@editor/utils/props';
|
|
28
31
|
|
|
@@ -32,18 +35,19 @@ class Props extends BaseService {
|
|
|
32
35
|
private state = reactive<PropsState>({
|
|
33
36
|
propsConfigMap: {},
|
|
34
37
|
propsValueMap: {},
|
|
38
|
+
relateIdMap: {},
|
|
35
39
|
});
|
|
36
40
|
|
|
37
41
|
constructor() {
|
|
38
42
|
super([
|
|
39
|
-
'setPropsConfig',
|
|
40
|
-
'getPropsConfig',
|
|
41
|
-
'setPropsValue',
|
|
42
|
-
'getPropsValue',
|
|
43
|
-
'createId',
|
|
44
|
-
'setNewItemId',
|
|
45
|
-
'fillConfig',
|
|
46
|
-
'getDefaultPropsValue',
|
|
43
|
+
{ name: 'setPropsConfig', isAsync: true },
|
|
44
|
+
{ name: 'getPropsConfig', isAsync: true },
|
|
45
|
+
{ name: 'setPropsValue', isAsync: true },
|
|
46
|
+
{ name: 'getPropsValue', isAsync: true },
|
|
47
|
+
{ name: 'createId', isAsync: false },
|
|
48
|
+
{ name: 'setNewItemId', isAsync: true },
|
|
49
|
+
{ name: 'fillConfig', isAsync: true },
|
|
50
|
+
{ name: 'getDefaultPropsValue', isAsync: true },
|
|
47
51
|
]);
|
|
48
52
|
}
|
|
49
53
|
|
|
@@ -135,11 +139,17 @@ class Props extends BaseService {
|
|
|
135
139
|
|
|
136
140
|
/**
|
|
137
141
|
* 将组件与组件的子元素配置中的id都设置成一个新的ID
|
|
142
|
+
* 如果没有相同ID并且force为false则保持不变
|
|
138
143
|
* @param {Object} config 组件配置
|
|
144
|
+
* @param {Boolean} force 是否强制设置新的ID
|
|
139
145
|
*/
|
|
140
146
|
/* eslint no-param-reassign: ["error", { "props": false }] */
|
|
141
|
-
public async setNewItemId(config: MNode) {
|
|
142
|
-
|
|
147
|
+
public async setNewItemId(config: MNode, force = true) {
|
|
148
|
+
if (force || editorService.getNodeById(config.id)) {
|
|
149
|
+
const newId = await this.createId(config.type || 'component');
|
|
150
|
+
this.setRelateId(config.id, newId);
|
|
151
|
+
config.id = newId;
|
|
152
|
+
}
|
|
143
153
|
|
|
144
154
|
if (config.items && Array.isArray(config.items)) {
|
|
145
155
|
for (const item of config.items) {
|
|
@@ -176,11 +186,59 @@ class Props extends BaseService {
|
|
|
176
186
|
this.state.propsValueMap = {};
|
|
177
187
|
}
|
|
178
188
|
|
|
189
|
+
/**
|
|
190
|
+
* 替换关联ID
|
|
191
|
+
* @param originConfigs 原组件配置
|
|
192
|
+
* @param targetConfigs 待替换的组件配置
|
|
193
|
+
*/
|
|
194
|
+
public replaceRelateId(originConfigs: MNode[], targetConfigs: MNode[]) {
|
|
195
|
+
const relateIdMap = this.getRelateIdMap();
|
|
196
|
+
if (Object.keys(relateIdMap).length === 0) return;
|
|
197
|
+
const target = depService.getTarget(DepTargetType.RELATED_COMP_WHEN_COPY, DepTargetType.RELATED_COMP_WHEN_COPY);
|
|
198
|
+
if (!target) return;
|
|
199
|
+
originConfigs.forEach((config: MNode) => {
|
|
200
|
+
const newId = relateIdMap[config.id];
|
|
201
|
+
const targetConfig = targetConfigs.find((targetConfig) => targetConfig.id === newId);
|
|
202
|
+
if (!targetConfig) return;
|
|
203
|
+
target.deps[config.id]?.keys?.forEach((fullKey) => {
|
|
204
|
+
const relateOriginId = get(config, fullKey);
|
|
205
|
+
const relateTargetId = relateIdMap[relateOriginId];
|
|
206
|
+
if (!relateTargetId) return;
|
|
207
|
+
set(targetConfig, fullKey, relateTargetId);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 清除setNewItemId前后映射关系
|
|
214
|
+
*/
|
|
215
|
+
public clearRelateId() {
|
|
216
|
+
this.state.relateIdMap = {};
|
|
217
|
+
}
|
|
218
|
+
|
|
179
219
|
public destroy() {
|
|
180
220
|
this.resetState();
|
|
181
221
|
this.removeAllListeners();
|
|
182
222
|
this.removeAllPlugins();
|
|
183
223
|
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 获取setNewItemId前后映射关系
|
|
227
|
+
* @param oldId 原组件ID
|
|
228
|
+
* @returns 新旧ID映射
|
|
229
|
+
*/
|
|
230
|
+
private getRelateIdMap() {
|
|
231
|
+
return this.state.relateIdMap;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 记录setNewItemId前后映射关系
|
|
236
|
+
* @param oldId 原组件ID
|
|
237
|
+
* @param newId 分配的新ID
|
|
238
|
+
*/
|
|
239
|
+
private setRelateId(oldId: Id, newId: Id) {
|
|
240
|
+
this.state.relateIdMap[oldId] = newId;
|
|
241
|
+
}
|
|
184
242
|
}
|
|
185
243
|
|
|
186
244
|
export type PropsService = Props;
|