@tmagic/editor 1.3.4 → 1.3.6
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/style.css +73 -51
- package/dist/tmagic-editor.js +1171 -1102
- package/dist/tmagic-editor.js.map +1 -1
- package/dist/tmagic-editor.umd.cjs +1188 -1119
- package/dist/tmagic-editor.umd.cjs.map +1 -1
- package/package.json +17 -17
- package/src/Editor.vue +5 -0
- package/src/components/FloatingBox.vue +117 -0
- package/src/components/Tree.vue +5 -0
- package/src/components/TreeNode.vue +8 -2
- package/src/editorProps.ts +7 -0
- package/src/hooks/use-filter.ts +55 -0
- package/src/hooks/use-node-status.ts +48 -0
- package/src/hooks/use-stage.ts +1 -0
- package/src/initService.ts +28 -12
- package/src/layouts/sidebar/Sidebar.vue +7 -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/LayerPanel.vue +24 -7
- package/src/layouts/sidebar/layer/use-node-status.ts +8 -11
- package/src/layouts/workspace/viewer/NodeListMenu.vue +67 -128
- package/src/layouts/workspace/viewer/Stage.vue +2 -1
- package/src/layouts/workspace/viewer/ViewerMenu.vue +1 -6
- 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 +66 -30
- package/src/services/props.ts +70 -12
- package/src/services/storage.ts +23 -13
- package/src/services/ui.ts +4 -1
- package/src/theme/floating-box.scss +30 -0
- package/src/theme/layer-panel.scss +19 -0
- 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 +6 -3
- package/src/utils/compose.ts +25 -6
- package/src/utils/content-menu.ts +4 -5
- package/src/utils/editor.ts +12 -3
- package/src/utils/operator.ts +1 -2
- 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 +1 -1
- package/types/components/Tree.vue.d.ts +27 -8
- package/types/components/TreeNode.vue.d.ts +24 -7
- package/types/editorProps.d.ts +7 -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/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/layouts/CodeEditor.vue.d.ts +4 -1
- package/types/layouts/Framework.vue.d.ts +1 -1
- package/types/layouts/PropsPanel.vue.d.ts +10 -4
- package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +1 -1
- package/types/layouts/sidebar/Sidebar.vue.d.ts +5 -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 +6 -2
- package/types/layouts/sidebar/layer/LayerPanel.vue.d.ts +1 -1
- package/types/layouts/sidebar/layer/use-click.d.ts +14 -5
- package/types/layouts/sidebar/layer/use-node-status.d.ts +3 -4
- package/types/layouts/workspace/Workspace.vue.d.ts +1 -1
- package/types/layouts/workspace/viewer/NodeListMenu.vue.d.ts +1 -14
- package/types/layouts/workspace/viewer/ViewerMenu.vue.d.ts +1 -1
- package/types/services/BaseService.d.ts +4 -1
- package/types/services/dep.d.ts +6 -5
- package/types/services/editor.d.ts +9 -3
- package/types/services/props.d.ts +25 -1
- package/types/services/storage.d.ts +7 -7
- package/types/type.d.ts +8 -6
- package/types/utils/compose.d.ts +1 -1
- package/types/utils/editor.d.ts +5 -1
- package/src/layouts/sidebar/layer/use-filter.ts +0 -59
- 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/viewer/NodeListMenuTitle.vue.d.ts +0 -15
|
@@ -1,112 +1,68 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
ref="
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
:
|
|
9
|
-
|
|
2
|
+
<TMagicTooltip v-if="page && buttonVisible" content="点击查看当前位置下的组件">
|
|
3
|
+
<div ref="button" class="m-editor-stage-float-button" @click="visible = true">可选组件</div>
|
|
4
|
+
</TMagicTooltip>
|
|
5
|
+
<FloatingBox
|
|
6
|
+
v-if="page && nodeStatusMap && buttonVisible"
|
|
7
|
+
ref="box"
|
|
8
|
+
v-model:visible="visible"
|
|
9
|
+
title="当前位置下的组件"
|
|
10
|
+
:position="menuPosition"
|
|
10
11
|
>
|
|
11
|
-
<template #
|
|
12
|
-
<
|
|
12
|
+
<template #body>
|
|
13
|
+
<Tree
|
|
14
|
+
class="m-editor-node-list-menu magic-editor-layer-tree"
|
|
15
|
+
:data="nodeData"
|
|
16
|
+
:node-status-map="nodeStatusMap"
|
|
17
|
+
@node-click="clickHandler"
|
|
18
|
+
></Tree>
|
|
13
19
|
</template>
|
|
14
|
-
</
|
|
20
|
+
</FloatingBox>
|
|
15
21
|
</template>
|
|
16
22
|
|
|
17
23
|
<script lang="ts" setup>
|
|
18
|
-
import {
|
|
19
|
-
import type { OnDrag } from 'gesto';
|
|
24
|
+
import { computed, inject, nextTick, ref, watch } from 'vue';
|
|
20
25
|
|
|
26
|
+
import { TMagicTooltip } from '@tmagic/design';
|
|
21
27
|
import type { MNode } from '@tmagic/schema';
|
|
22
|
-
import { StageDragStatus } from '@tmagic/stage';
|
|
23
|
-
import { getNodes } from '@tmagic/utils';
|
|
24
28
|
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
|
|
28
|
-
import
|
|
29
|
-
|
|
30
|
-
const PINNED_STATUE_CACHE_KEY = 'tmagic-pinned-node-list-pinned-status';
|
|
31
|
-
|
|
32
|
-
const props = defineProps<{ isMultiSelect?: boolean }>();
|
|
33
|
-
|
|
34
|
-
const menu = ref<InstanceType<typeof ContentMenu>>();
|
|
35
|
-
const nodeList = ref<MNode[]>([]);
|
|
36
|
-
const pinned = ref(Boolean(globalThis.localStorage.getItem(PINNED_STATUE_CACHE_KEY)));
|
|
37
|
-
const firstShow = ref(true);
|
|
29
|
+
import FloatingBox from '@editor/components/FloatingBox.vue';
|
|
30
|
+
import Tree from '@editor/components/Tree.vue';
|
|
31
|
+
import { useFilter } from '@editor/hooks/use-filter';
|
|
32
|
+
import { useNodeStatus } from '@editor/layouts/sidebar/layer/use-node-status';
|
|
33
|
+
import type { Services, TreeNodeData } from '@editor/type';
|
|
38
34
|
|
|
39
35
|
const services = inject<Services>('services');
|
|
40
36
|
const editorService = services?.editorService;
|
|
41
|
-
|
|
37
|
+
|
|
38
|
+
const visible = ref(false);
|
|
39
|
+
const buttonVisible = ref(false);
|
|
40
|
+
const button = ref<HTMLDivElement>();
|
|
41
|
+
const box = ref<InstanceType<typeof FloatingBox>>();
|
|
42
42
|
|
|
43
43
|
const stage = computed(() => editorService?.get('stage'));
|
|
44
44
|
const page = computed(() => editorService?.get('page'));
|
|
45
|
-
const
|
|
45
|
+
const nodes = computed(() => editorService?.get('nodes') || []);
|
|
46
|
+
const nodeData = computed<TreeNodeData[]>(() => (!page.value ? [] : [page.value]));
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
const { nodeStatusMap } = useNodeStatus(services);
|
|
48
49
|
|
|
49
|
-
const
|
|
50
|
-
if (timeout) {
|
|
51
|
-
globalThis.clearTimeout(timeout);
|
|
52
|
-
}
|
|
50
|
+
const filterNodeMethod = (value: string, data: MNode): boolean => data.id === value;
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
nodeList.value = [];
|
|
59
|
-
menu.value?.hide();
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const clearTimeoutLazy = () => {
|
|
63
|
-
globalThis.setTimeout(() => {
|
|
64
|
-
if (timeout) {
|
|
65
|
-
globalThis.clearTimeout(timeout);
|
|
66
|
-
}
|
|
67
|
-
}, 300);
|
|
68
|
-
};
|
|
52
|
+
const { filterTextChangeHandler } = useFilter(nodeData, nodeStatusMap, filterNodeMethod);
|
|
69
53
|
|
|
70
54
|
const unWatch = watch(
|
|
71
55
|
stage,
|
|
72
56
|
(stage) => {
|
|
73
57
|
if (!stage) return;
|
|
74
58
|
|
|
75
|
-
stage.on('
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
stage.on('mousemove', (event: MouseEvent) => {
|
|
80
|
-
cancel();
|
|
81
|
-
|
|
82
|
-
if (props.isMultiSelect || stage.getDragStatus() !== StageDragStatus.END) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
timeout = globalThis.setTimeout(() => {
|
|
87
|
-
const els = stage.renderer.getElementsFromPoint(event) || [];
|
|
59
|
+
stage.on('select', (el: HTMLElement, event: MouseEvent) => {
|
|
60
|
+
const els = stage.renderer.getElementsFromPoint(event) || [];
|
|
61
|
+
const ids = els.map((el) => el.id).filter((id) => Boolean(id));
|
|
88
62
|
|
|
89
|
-
|
|
90
|
-
els.map((el) => el.id),
|
|
91
|
-
page.value?.items,
|
|
92
|
-
);
|
|
63
|
+
buttonVisible.value = ids.length > 3;
|
|
93
64
|
|
|
94
|
-
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
nodeList.value = nodes;
|
|
99
|
-
|
|
100
|
-
if (nodeList.value.length > 1) {
|
|
101
|
-
menu.value?.show(pinned.value && !firstShow.value ? undefined : event);
|
|
102
|
-
firstShow.value = false;
|
|
103
|
-
}
|
|
104
|
-
}, 1500);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
stage.on('mouseleave', () => {
|
|
108
|
-
// mouseleave后,大概率还有最后一个mousemove事件,这里延迟清除
|
|
109
|
-
clearTimeoutLazy();
|
|
65
|
+
filterTextChangeHandler(ids);
|
|
110
66
|
});
|
|
111
67
|
|
|
112
68
|
unWatch();
|
|
@@ -116,60 +72,43 @@ const unWatch = watch(
|
|
|
116
72
|
},
|
|
117
73
|
);
|
|
118
74
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
map[item.type] = item;
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
return map;
|
|
127
|
-
});
|
|
75
|
+
watch(
|
|
76
|
+
nodes,
|
|
77
|
+
(nodes) => {
|
|
78
|
+
if (!nodeStatusMap.value) return;
|
|
128
79
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
let text = node.name;
|
|
132
|
-
let icon: string | Component<{}, {}, any> | undefined;
|
|
133
|
-
if (node.type) {
|
|
134
|
-
const item = componentMap.value[node.type];
|
|
135
|
-
text += ` (${item?.text})`;
|
|
136
|
-
icon = item?.icon;
|
|
80
|
+
for (const [id, status] of nodeStatusMap.value.entries()) {
|
|
81
|
+
status.selected = nodes.some((node) => node.id === id);
|
|
137
82
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
id: node.id,
|
|
143
|
-
icon,
|
|
144
|
-
handler: async () => {
|
|
145
|
-
await editorService?.select(node);
|
|
146
|
-
stage.value?.select(node.id);
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
}),
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
immediate: true,
|
|
86
|
+
},
|
|
150
87
|
);
|
|
151
88
|
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
89
|
+
const clickHandler = async (event: MouseEvent, data: TreeNodeData) => {
|
|
90
|
+
await editorService?.select(data.id);
|
|
91
|
+
stage.value?.select(data.id);
|
|
155
92
|
};
|
|
156
93
|
|
|
157
|
-
const
|
|
158
|
-
|
|
94
|
+
const menuPosition = ref({
|
|
95
|
+
left: 0,
|
|
96
|
+
top: 0,
|
|
97
|
+
});
|
|
159
98
|
|
|
160
|
-
|
|
99
|
+
watch(visible, async (visible) => {
|
|
100
|
+
if (!button.value || !visible) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
161
103
|
|
|
162
|
-
|
|
163
|
-
clientY: menuPosition.top + deltaY,
|
|
164
|
-
clientX: menuPosition.left + deltaX,
|
|
165
|
-
});
|
|
166
|
-
};
|
|
104
|
+
await nextTick();
|
|
167
105
|
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
};
|
|
106
|
+
const rect = button.value.getBoundingClientRect();
|
|
107
|
+
const height = box.value?.target?.clientHeight || 0;
|
|
171
108
|
|
|
172
|
-
|
|
173
|
-
|
|
109
|
+
menuPosition.value = {
|
|
110
|
+
left: rect.left + rect.width + 5,
|
|
111
|
+
top: rect.top - height / 2 + rect.height / 2,
|
|
112
|
+
};
|
|
174
113
|
});
|
|
175
114
|
</script>
|
|
@@ -22,9 +22,10 @@
|
|
|
22
22
|
@drop="dropHandler"
|
|
23
23
|
@dragover="dragoverHandler"
|
|
24
24
|
></div>
|
|
25
|
+
<NodeListMenu></NodeListMenu>
|
|
26
|
+
|
|
25
27
|
<Teleport to="body">
|
|
26
28
|
<ViewerMenu ref="menu" :is-multi-select="isMultiSelect" :stage-content-menu="stageContentMenu"></ViewerMenu>
|
|
27
|
-
<NodeListMenu ref="nodeList" :is-multi-select="isMultiSelect"></NodeListMenu>
|
|
28
29
|
</Teleport>
|
|
29
30
|
</ScrollViewer>
|
|
30
31
|
</template>
|
|
@@ -11,10 +11,8 @@ import { isPage } from '@tmagic/utils';
|
|
|
11
11
|
|
|
12
12
|
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
13
13
|
import CenterIcon from '@editor/icons/CenterIcon.vue';
|
|
14
|
-
import storageService from '@editor/services/storage';
|
|
15
14
|
import { LayerOffset, Layout, MenuButton, MenuComponent, Services } from '@editor/type';
|
|
16
15
|
import { useCopyMenu, useDeleteMenu, useMoveToMenu, usePasteMenu } from '@editor/utils/content-menu';
|
|
17
|
-
import { COPY_STORAGE_KEY } from '@editor/utils/editor';
|
|
18
16
|
|
|
19
17
|
defineOptions({
|
|
20
18
|
name: 'MEditorViewerMenu',
|
|
@@ -28,7 +26,6 @@ const props = withDefaults(
|
|
|
28
26
|
const services = inject<Services>('services');
|
|
29
27
|
const editorService = services?.editorService;
|
|
30
28
|
const menu = ref<InstanceType<typeof ContentMenu>>();
|
|
31
|
-
const canPaste = ref(false);
|
|
32
29
|
const canCenter = ref(false);
|
|
33
30
|
|
|
34
31
|
const node = computed(() => editorService?.get('node'));
|
|
@@ -127,10 +124,8 @@ watch(
|
|
|
127
124
|
{ immediate: true },
|
|
128
125
|
);
|
|
129
126
|
|
|
130
|
-
const show =
|
|
127
|
+
const show = (e: MouseEvent) => {
|
|
131
128
|
menu.value?.show(e);
|
|
132
|
-
const data = await storageService.getItem(COPY_STORAGE_KEY);
|
|
133
|
-
canPaste.value = data !== 'undefined' && !!data;
|
|
134
129
|
};
|
|
135
130
|
|
|
136
131
|
defineExpose({ show });
|
|
@@ -24,13 +24,48 @@ const methodName = (prefix: string, name: string) => `${prefix}${name[0].toUpper
|
|
|
24
24
|
|
|
25
25
|
const isError = (error: any): boolean => Object.prototype.toString.call(error) === '[object Error]';
|
|
26
26
|
|
|
27
|
-
const doAction =
|
|
27
|
+
const doAction = (
|
|
28
28
|
args: any[],
|
|
29
29
|
scope: any,
|
|
30
30
|
sourceMethod: any,
|
|
31
31
|
beforeMethodName: string,
|
|
32
32
|
afterMethodName: string,
|
|
33
|
-
fn: (args: any[], next?: Function | undefined) =>
|
|
33
|
+
fn: (args: any[], next?: Function | undefined) => void,
|
|
34
|
+
) => {
|
|
35
|
+
try {
|
|
36
|
+
let beforeArgs = args;
|
|
37
|
+
|
|
38
|
+
for (const beforeMethod of scope.pluginOptionsList[beforeMethodName]) {
|
|
39
|
+
beforeArgs = beforeMethod(...beforeArgs) || [];
|
|
40
|
+
|
|
41
|
+
if (isError(beforeArgs)) throw beforeArgs;
|
|
42
|
+
|
|
43
|
+
if (!Array.isArray(beforeArgs)) {
|
|
44
|
+
beforeArgs = [beforeArgs];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let returnValue: any = fn(beforeArgs, sourceMethod.bind(scope));
|
|
49
|
+
|
|
50
|
+
for (const afterMethod of scope.pluginOptionsList[afterMethodName]) {
|
|
51
|
+
returnValue = afterMethod(returnValue, ...beforeArgs);
|
|
52
|
+
|
|
53
|
+
if (isError(returnValue)) throw returnValue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return returnValue;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const doAsyncAction = async (
|
|
63
|
+
args: any[],
|
|
64
|
+
scope: any,
|
|
65
|
+
sourceMethod: any,
|
|
66
|
+
beforeMethodName: string,
|
|
67
|
+
afterMethodName: string,
|
|
68
|
+
fn: (args: any[], next?: Function | undefined) => Promise<void> | void,
|
|
34
69
|
) => {
|
|
35
70
|
try {
|
|
36
71
|
let beforeArgs = args;
|
|
@@ -112,10 +147,10 @@ export default class extends EventEmitter {
|
|
|
112
147
|
private taskList: (() => Promise<void>)[] = [];
|
|
113
148
|
private doingTask = false;
|
|
114
149
|
|
|
115
|
-
constructor(methods: string[] = [], serialMethods: string[] = []) {
|
|
150
|
+
constructor(methods: { name: string; isAsync: boolean }[] = [], serialMethods: string[] = []) {
|
|
116
151
|
super();
|
|
117
152
|
|
|
118
|
-
methods.forEach((
|
|
153
|
+
methods.forEach(({ name: propertyName, isAsync }) => {
|
|
119
154
|
const scope = this as any;
|
|
120
155
|
|
|
121
156
|
const sourceMethod = scope[propertyName];
|
|
@@ -127,32 +162,34 @@ export default class extends EventEmitter {
|
|
|
127
162
|
this.pluginOptionsList[afterMethodName] = [];
|
|
128
163
|
this.middleware[propertyName] = [];
|
|
129
164
|
|
|
130
|
-
const fn = compose(this.middleware[propertyName]);
|
|
165
|
+
const fn = compose(this.middleware[propertyName], isAsync);
|
|
131
166
|
Object.defineProperty(scope, propertyName, {
|
|
132
|
-
value:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// 由于async await,所以会出现函数执行到await时让出线程,导致执行顺序出错,例如调用了select(1) -> update -> select(2),这个时候就有可能出现update了2;
|
|
138
|
-
// 这里保证函数调用严格按顺序执行;
|
|
139
|
-
const promise = new Promise<any>((resolve, reject) => {
|
|
140
|
-
this.taskList.push(async () => {
|
|
141
|
-
try {
|
|
142
|
-
const value = await doAction(args, scope, sourceMethod, beforeMethodName, afterMethodName, fn);
|
|
143
|
-
resolve(value);
|
|
144
|
-
} catch (e) {
|
|
145
|
-
reject(e);
|
|
167
|
+
value: isAsync
|
|
168
|
+
? async (...args: any[]) => {
|
|
169
|
+
if (!serialMethods.includes(propertyName)) {
|
|
170
|
+
return doAsyncAction(args, scope, sourceMethod, beforeMethodName, afterMethodName, fn);
|
|
146
171
|
}
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
172
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
173
|
+
// 由于async await,所以会出现函数执行到await时让出线程,导致执行顺序出错,例如调用了select(1) -> update -> select(2),这个时候就有可能出现update了2;
|
|
174
|
+
// 这里保证函数调用严格按顺序执行;
|
|
175
|
+
const promise = new Promise<any>((resolve, reject) => {
|
|
176
|
+
this.taskList.push(async () => {
|
|
177
|
+
try {
|
|
178
|
+
const value = await doAsyncAction(args, scope, sourceMethod, beforeMethodName, afterMethodName, fn);
|
|
179
|
+
resolve(value);
|
|
180
|
+
} catch (e) {
|
|
181
|
+
reject(e);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (!this.doingTask) {
|
|
187
|
+
this.doTask();
|
|
188
|
+
}
|
|
153
189
|
|
|
154
|
-
|
|
155
|
-
|
|
190
|
+
return promise;
|
|
191
|
+
}
|
|
192
|
+
: (...args: any[]) => doAction(args, scope, sourceMethod, beforeMethodName, afterMethodName, fn),
|
|
156
193
|
});
|
|
157
194
|
});
|
|
158
195
|
}
|
|
@@ -38,7 +38,13 @@ class CodeBlock extends BaseService {
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
constructor() {
|
|
41
|
-
super([
|
|
41
|
+
super([
|
|
42
|
+
{ name: 'setCodeDslById', isAsync: true },
|
|
43
|
+
{ name: 'setEditStatus', isAsync: true },
|
|
44
|
+
{ name: 'setCombineIds', isAsync: true },
|
|
45
|
+
{ name: 'setUndeleteableList', isAsync: true },
|
|
46
|
+
{ name: 'deleteCodeDslByIds', isAsync: true },
|
|
47
|
+
]);
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
/**
|
package/src/services/dep.ts
CHANGED
|
@@ -35,8 +35,8 @@ class Dep extends BaseService {
|
|
|
35
35
|
return this.watcher.getTargets(type);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
public getTarget(id: Id) {
|
|
39
|
-
return this.watcher.getTarget(id);
|
|
38
|
+
public getTarget(id: Id, type: string = DepTargetType.DEFAULT) {
|
|
39
|
+
return this.watcher.getTarget(id, type);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
public addTarget(target: Target) {
|
|
@@ -44,8 +44,8 @@ class Dep extends BaseService {
|
|
|
44
44
|
this.emit('add-target', target);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
public removeTarget(id: Id) {
|
|
48
|
-
this.watcher.removeTarget(id);
|
|
47
|
+
public removeTarget(id: Id, type: string = DepTargetType.DEFAULT) {
|
|
48
|
+
this.watcher.removeTarget(id, type);
|
|
49
49
|
this.emit('remove-target');
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -53,8 +53,8 @@ class Dep extends BaseService {
|
|
|
53
53
|
this.watcher.clearTargets();
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
public collect(nodes: MNode[], deep = false) {
|
|
57
|
-
this.watcher.collect(nodes, deep);
|
|
56
|
+
public collect(nodes: MNode[], deep = false, type?: DepTargetType) {
|
|
57
|
+
this.watcher.collect(nodes, deep, type);
|
|
58
58
|
this.emit('collected', nodes, deep);
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -62,8 +62,12 @@ class Dep extends BaseService {
|
|
|
62
62
|
return this.watcher.clear(nodes);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
public hasTarget(id: Id) {
|
|
66
|
-
return this.watcher.hasTarget(id);
|
|
65
|
+
public hasTarget(id: Id, type: string = DepTargetType.DEFAULT) {
|
|
66
|
+
return this.watcher.hasTarget(id, type);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public hasSpecifiedTypeTarget(type: string = DepTargetType.DEFAULT): boolean {
|
|
70
|
+
return this.watcher.hasSpecifiedTypeTarget(type);
|
|
67
71
|
}
|
|
68
72
|
}
|
|
69
73
|
|
package/src/services/editor.ts
CHANGED
|
@@ -17,13 +17,15 @@
|
|
|
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 { DepTargetType } from '@tmagic/dep';
|
|
22
23
|
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
23
24
|
import { NodeType } from '@tmagic/schema';
|
|
24
25
|
import StageCore from '@tmagic/stage';
|
|
25
26
|
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
|
26
27
|
|
|
28
|
+
import depService from '@editor/services/dep';
|
|
27
29
|
import historyService from '@editor/services/history';
|
|
28
30
|
import storageService, { Protocol } from '@editor/services/storage';
|
|
29
31
|
import type { AddMNode, EditorNodeInfo, PastePosition, StepValue, StoreState, StoreStateKey } from '@editor/type';
|
|
@@ -61,27 +63,27 @@ class Editor extends BaseService {
|
|
|
61
63
|
constructor() {
|
|
62
64
|
super(
|
|
63
65
|
[
|
|
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',
|
|
66
|
+
{ name: 'getLayout', isAsync: true },
|
|
67
|
+
{ name: 'select', isAsync: true },
|
|
68
|
+
{ name: 'doAdd', isAsync: true },
|
|
69
|
+
{ name: 'add', isAsync: true },
|
|
70
|
+
{ name: 'doRemove', isAsync: true },
|
|
71
|
+
{ name: 'remove', isAsync: true },
|
|
72
|
+
{ name: 'doUpdate', isAsync: true },
|
|
73
|
+
{ name: 'update', isAsync: true },
|
|
74
|
+
{ name: 'sort', isAsync: true },
|
|
75
|
+
{ name: 'copy', isAsync: true },
|
|
76
|
+
{ name: 'paste', isAsync: true },
|
|
77
|
+
{ name: 'doPaste', isAsync: true },
|
|
78
|
+
{ name: 'doAlignCenter', isAsync: true },
|
|
79
|
+
{ name: 'alignCenter', isAsync: true },
|
|
80
|
+
{ name: 'moveLayer', isAsync: true },
|
|
81
|
+
{ name: 'moveToContainer', isAsync: true },
|
|
82
|
+
{ name: 'move', isAsync: true },
|
|
83
|
+
{ name: 'undo', isAsync: true },
|
|
84
|
+
{ name: 'redo', isAsync: true },
|
|
85
|
+
{ name: 'highlight', isAsync: true },
|
|
86
|
+
{ name: 'dragTo', isAsync: true },
|
|
85
87
|
],
|
|
86
88
|
// 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用
|
|
87
89
|
['select', 'update', 'moveLayer'],
|
|
@@ -593,12 +595,47 @@ class Editor extends BaseService {
|
|
|
593
595
|
}
|
|
594
596
|
|
|
595
597
|
/**
|
|
596
|
-
*
|
|
598
|
+
* 将组件节点配置存储到localStorage中
|
|
597
599
|
* @param config 组件节点配置
|
|
598
|
-
* @returns
|
|
600
|
+
* @returns
|
|
599
601
|
*/
|
|
600
|
-
public
|
|
601
|
-
|
|
602
|
+
public copy(config: MNode | MNode[]): void {
|
|
603
|
+
storageService.setItem(COPY_STORAGE_KEY, Array.isArray(config) ? config : [config], {
|
|
604
|
+
protocol: Protocol.OBJECT,
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* 复制时会带上组件关联的依赖
|
|
610
|
+
* @param config 组件节点配置
|
|
611
|
+
* @returns
|
|
612
|
+
*/
|
|
613
|
+
public copyWithRelated(config: MNode | MNode[]): void {
|
|
614
|
+
const copyNodes: MNode[] = Array.isArray(config) ? config : [config];
|
|
615
|
+
// 关联的组件也一并复制
|
|
616
|
+
depService.getTarget(DepTargetType.RELATED_COMP_WHEN_COPY, DepTargetType.RELATED_COMP_WHEN_COPY)?.removeDep();
|
|
617
|
+
depService.collect(copyNodes, true, DepTargetType.RELATED_COMP_WHEN_COPY);
|
|
618
|
+
const customTarget = depService.getTarget(
|
|
619
|
+
DepTargetType.RELATED_COMP_WHEN_COPY,
|
|
620
|
+
DepTargetType.RELATED_COMP_WHEN_COPY,
|
|
621
|
+
);
|
|
622
|
+
if (customTarget) {
|
|
623
|
+
Object.keys(customTarget.deps).forEach((nodeId: Id) => {
|
|
624
|
+
const node = this.getNodeById(nodeId);
|
|
625
|
+
if (!node) return;
|
|
626
|
+
customTarget!.deps[nodeId].keys.forEach((key) => {
|
|
627
|
+
const relateNodeId = get(node, key);
|
|
628
|
+
const isExist = copyNodes.find((node) => node.id === relateNodeId);
|
|
629
|
+
if (!isExist) {
|
|
630
|
+
const relateNode = this.getNodeById(relateNodeId);
|
|
631
|
+
if (relateNode) {
|
|
632
|
+
copyNodes.push(relateNode);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
storageService.setItem(COPY_STORAGE_KEY, copyNodes, {
|
|
602
639
|
protocol: Protocol.OBJECT,
|
|
603
640
|
});
|
|
604
641
|
}
|
|
@@ -609,8 +646,7 @@ class Editor extends BaseService {
|
|
|
609
646
|
* @returns 添加后的组件节点配置
|
|
610
647
|
*/
|
|
611
648
|
public async paste(position: PastePosition = {}): Promise<MNode | MNode[] | void> {
|
|
612
|
-
const config: MNode[] =
|
|
613
|
-
|
|
649
|
+
const config: MNode[] = storageService.getItem(COPY_STORAGE_KEY);
|
|
614
650
|
if (!Array.isArray(config)) return;
|
|
615
651
|
|
|
616
652
|
const node = this.get('node');
|
|
@@ -623,13 +659,13 @@ class Editor extends BaseService {
|
|
|
623
659
|
parent = this.get('page');
|
|
624
660
|
}
|
|
625
661
|
}
|
|
626
|
-
|
|
627
662
|
const pasteConfigs = await this.doPaste(config, position);
|
|
628
|
-
|
|
663
|
+
propsService.replaceRelateId(config, pasteConfigs);
|
|
629
664
|
return this.add(pasteConfigs, parent);
|
|
630
665
|
}
|
|
631
666
|
|
|
632
667
|
public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
|
|
668
|
+
propsService.clearRelateId();
|
|
633
669
|
const pasteConfigs = await beforePaste(position, cloneDeep(config));
|
|
634
670
|
return pasteConfigs;
|
|
635
671
|
}
|