@tmagic/editor 1.2.0-beta.9 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +59 -35
- package/dist/{tmagic-editor.mjs → tmagic-editor.js} +1473 -1154
- package/dist/tmagic-editor.js.map +1 -0
- package/dist/{tmagic-editor.umd.js → tmagic-editor.umd.cjs} +1483 -1159
- package/dist/tmagic-editor.umd.cjs.map +1 -0
- package/package.json +16 -14
- package/src/Editor.vue +66 -40
- package/src/components/CodeDraftEditor.vue +145 -0
- package/src/components/ContentMenu.vue +1 -1
- package/src/components/FunctionEditor.vue +145 -0
- package/src/components/Icon.vue +1 -1
- package/src/{layouts → components}/Layout.vue +54 -15
- package/src/components/ScrollBar.vue +1 -1
- package/src/components/ScrollViewer.vue +10 -1
- package/src/components/ToolButton.vue +1 -1
- package/src/fields/Code.vue +1 -1
- package/src/fields/CodeLink.vue +1 -1
- package/src/fields/CodeSelect.vue +89 -102
- package/src/fields/UISelect.vue +1 -1
- package/src/index.ts +1 -0
- package/src/layouts/AddPageBox.vue +1 -1
- package/src/layouts/CodeEditor.vue +2 -3
- package/src/layouts/Framework.vue +2 -2
- package/src/layouts/NavMenu.vue +2 -2
- package/src/layouts/PropsPanel.vue +13 -6
- package/src/layouts/Resizer.vue +1 -1
- package/src/layouts/sidebar/ComponentListPanel.vue +1 -1
- package/src/layouts/sidebar/LayerMenu.vue +9 -7
- package/src/layouts/sidebar/LayerPanel.vue +127 -174
- package/src/layouts/sidebar/Sidebar.vue +110 -26
- package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +27 -83
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +90 -122
- package/src/layouts/workspace/Breadcrumb.vue +1 -1
- package/src/layouts/workspace/PageBar.vue +1 -1
- package/src/layouts/workspace/PageBarScrollContainer.vue +1 -1
- package/src/layouts/workspace/Stage.vue +26 -9
- package/src/layouts/workspace/ViewerMenu.vue +11 -9
- package/src/layouts/workspace/Workspace.vue +7 -3
- package/src/services/BaseService.ts +10 -1
- package/src/services/codeBlock.ts +124 -125
- package/src/services/componentList.ts +6 -1
- package/src/services/editor.ts +54 -18
- package/src/services/events.ts +6 -1
- package/src/services/history.ts +7 -16
- package/src/services/props.ts +7 -2
- package/src/services/storage.ts +1 -0
- package/src/services/ui.ts +12 -0
- package/src/theme/code-block.scss +43 -24
- package/src/theme/component-list-panel.scss +8 -5
- package/src/type.ts +77 -50
- package/src/utils/editor.ts +9 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/props.ts +2 -2
- package/src/utils/scroll-viewer.ts +18 -2
- package/src/utils/stage.ts +4 -3
- package/types/Editor.vue.d.ts +47 -27
- package/types/components/CodeDraftEditor.vue.d.ts +56 -0
- package/types/components/ContentMenu.vue.d.ts +11 -87
- package/types/components/FunctionEditor.vue.d.ts +43 -0
- package/types/components/Icon.vue.d.ts +4 -50
- package/types/{layouts → components}/Layout.vue.d.ts +12 -1
- package/types/components/ScrollBar.vue.d.ts +7 -65
- package/types/components/ScrollViewer.vue.d.ts +45 -1
- package/types/components/ToolButton.vue.d.ts +12 -78
- package/types/fields/Code.vue.d.ts +11 -77
- package/types/fields/CodeLink.vue.d.ts +12 -82
- package/types/fields/CodeSelect.vue.d.ts +13 -77
- package/types/fields/UISelect.vue.d.ts +7 -65
- package/types/index.d.ts +1 -0
- package/types/layouts/AddPageBox.vue.d.ts +1 -43
- package/types/layouts/CodeEditor.vue.d.ts +22 -130
- package/types/layouts/NavMenu.vue.d.ts +9 -69
- package/types/layouts/sidebar/LayerMenu.vue.d.ts +16 -48
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +24 -7
- package/types/layouts/sidebar/Sidebar.vue.d.ts +10 -5
- package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +1 -1
- package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +6 -5
- package/types/layouts/workspace/Breadcrumb.vue.d.ts +1 -43
- package/types/layouts/workspace/Stage.vue.d.ts +15 -43
- package/types/layouts/workspace/ViewerMenu.vue.d.ts +11 -66
- package/types/layouts/workspace/Workspace.vue.d.ts +23 -5
- package/types/services/BaseService.d.ts +2 -1
- package/types/services/codeBlock.d.ts +57 -36
- package/types/services/componentList.d.ts +1 -0
- package/types/services/editor.d.ts +5 -6
- package/types/services/events.d.ts +1 -0
- package/types/services/history.d.ts +5 -15
- package/types/services/props.d.ts +3 -2
- package/types/services/ui.d.ts +2 -1
- package/types/type.d.ts +65 -48
- package/types/utils/editor.d.ts +1 -0
- package/types/utils/index.d.ts +1 -0
- package/types/utils/props.d.ts +1 -1
- package/types/utils/scroll-viewer.d.ts +5 -0
- package/dist/tmagic-editor.mjs.map +0 -1
- package/dist/tmagic-editor.umd.js.map +0 -1
- package/src/layouts/sidebar/TabPane.vue +0 -118
- package/types/layouts/sidebar/TabPane.vue.d.ts +0 -82
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<Breadcrumb></Breadcrumb>
|
|
4
4
|
|
|
5
5
|
<slot name="stage">
|
|
6
|
-
<MagicStage
|
|
6
|
+
<MagicStage v-if="page" :stage-content-menu="stageContentMenu"></MagicStage>
|
|
7
7
|
</slot>
|
|
8
8
|
|
|
9
9
|
<slot name="workspace-content"></slot>
|
|
@@ -15,19 +15,23 @@
|
|
|
15
15
|
</div>
|
|
16
16
|
</template>
|
|
17
17
|
|
|
18
|
-
<script lang="ts" setup>
|
|
18
|
+
<script lang="ts" setup name="MEditorWorkspace">
|
|
19
19
|
import { computed, inject, onMounted, onUnmounted, ref } from 'vue';
|
|
20
20
|
import KeyController from 'keycon';
|
|
21
21
|
|
|
22
22
|
import type { MNode, MPage } from '@tmagic/schema';
|
|
23
23
|
import { isPage } from '@tmagic/utils';
|
|
24
24
|
|
|
25
|
-
import type { Services } from '../../type';
|
|
25
|
+
import type { MenuButton, MenuComponent, Services } from '../../type';
|
|
26
26
|
|
|
27
27
|
import Breadcrumb from './Breadcrumb.vue';
|
|
28
28
|
import PageBar from './PageBar.vue';
|
|
29
29
|
import MagicStage from './Stage.vue';
|
|
30
30
|
|
|
31
|
+
defineProps<{
|
|
32
|
+
stageContentMenu: (MenuButton | MenuComponent)[];
|
|
33
|
+
}>();
|
|
34
|
+
|
|
31
35
|
const services = inject<Services>('services');
|
|
32
36
|
const workspace = ref<HTMLDivElement>();
|
|
33
37
|
const nodes = computed(() => services?.editorService.get<MNode[]>('nodes'));
|
|
@@ -77,7 +77,7 @@ const doAction = async (
|
|
|
77
77
|
*
|
|
78
78
|
* editorService.usePlugin({
|
|
79
79
|
* beforeAdd(value) { return [value] },
|
|
80
|
-
* afterAdd(
|
|
80
|
+
* afterAdd(result, value) { return result },
|
|
81
81
|
* });
|
|
82
82
|
*
|
|
83
83
|
* editorService.add(); 最终会变成 () => {
|
|
@@ -169,6 +169,15 @@ export default class extends EventEmitter {
|
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
public removeAllPlugins() {
|
|
173
|
+
Object.keys(this.pluginOptionsList).forEach((key) => {
|
|
174
|
+
this.pluginOptionsList[key] = [];
|
|
175
|
+
});
|
|
176
|
+
Object.keys(this.middleware).forEach((key) => {
|
|
177
|
+
this.middleware[key] = [];
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
172
181
|
private async doTask() {
|
|
173
182
|
this.doingTask = true;
|
|
174
183
|
let task = this.taskList.shift();
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
import { reactive } from 'vue';
|
|
20
20
|
import { cloneDeep, forIn, isEmpty, keys, omit, pick } from 'lodash-es';
|
|
21
21
|
|
|
22
|
-
import { Id, MNode } from '@tmagic/schema';
|
|
22
|
+
import { CodeBlockContent, CodeBlockDSL, HookType, Id, MApp, MNode } from '@tmagic/schema';
|
|
23
23
|
|
|
24
24
|
import editorService from '../services/editor';
|
|
25
|
-
import type {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
25
|
+
import type { CodeRelation, CodeState, HookData } from '../type';
|
|
26
|
+
import { CODE_DRAFT_STORAGE_KEY, CodeEditorMode } from '../type';
|
|
27
|
+
import { info } from '../utils/logger';
|
|
28
28
|
|
|
29
29
|
import BaseService from './BaseService';
|
|
30
30
|
|
|
@@ -37,6 +37,7 @@ class CodeBlock extends BaseService {
|
|
|
37
37
|
mode: CodeEditorMode.EDITOR,
|
|
38
38
|
combineIds: [],
|
|
39
39
|
undeletableList: [],
|
|
40
|
+
relations: {},
|
|
40
41
|
});
|
|
41
42
|
|
|
42
43
|
constructor() {
|
|
@@ -70,22 +71,27 @@ class CodeBlock extends BaseService {
|
|
|
70
71
|
|
|
71
72
|
/**
|
|
72
73
|
* 获取活动的代码块dsl数据源(默认从dsl中的codeBlocks字段读取)
|
|
74
|
+
* 方法要支持钩子添加扩展,会被重写为异步方法,因此这里显示写为异步以提醒调用者需以异步形式调用
|
|
73
75
|
* @param {boolean} forceRefresh 是否强制从活动dsl拉取刷新
|
|
74
76
|
* @returns {CodeBlockDSL | null}
|
|
75
77
|
*/
|
|
76
78
|
public async getCodeDsl(forceRefresh = false): Promise<CodeBlockDSL | null> {
|
|
79
|
+
return this.getCodeDslSync(forceRefresh);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public getCodeDslSync(forceRefresh = false): CodeBlockDSL | null {
|
|
77
83
|
if (!this.state.codeDsl || forceRefresh) {
|
|
78
|
-
this.state.codeDsl =
|
|
84
|
+
this.state.codeDsl = editorService.getCodeDslSync();
|
|
79
85
|
}
|
|
80
86
|
return this.state.codeDsl;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
89
|
/**
|
|
84
90
|
* 根据代码块id获取代码块内容
|
|
85
|
-
* @param {
|
|
91
|
+
* @param {Id} id 代码块id
|
|
86
92
|
* @returns {CodeBlockContent | null}
|
|
87
93
|
*/
|
|
88
|
-
public async getCodeContentById(id:
|
|
94
|
+
public async getCodeContentById(id: Id): Promise<CodeBlockContent | null> {
|
|
89
95
|
if (!id) return null;
|
|
90
96
|
const totalCodeDsl = await this.getCodeDsl();
|
|
91
97
|
if (!totalCodeDsl) return null;
|
|
@@ -94,16 +100,24 @@ class CodeBlock extends BaseService {
|
|
|
94
100
|
|
|
95
101
|
/**
|
|
96
102
|
* 设置代码块ID和代码内容到源dsl
|
|
97
|
-
* @param {
|
|
103
|
+
* @param {Id} id 代码块id
|
|
98
104
|
* @param {CodeBlockContent} codeConfig 代码块内容配置信息
|
|
99
105
|
* @returns {void}
|
|
100
106
|
*/
|
|
101
|
-
public async setCodeDslById(id:
|
|
107
|
+
public async setCodeDslById(id: Id, codeConfig: CodeBlockContent): Promise<void> {
|
|
102
108
|
let codeDsl = await this.getCodeDsl();
|
|
109
|
+
const codeConfigProcessed = codeConfig;
|
|
110
|
+
if (codeConfig.content) {
|
|
111
|
+
// 在保存的时候转换代码内容
|
|
112
|
+
// eslint-disable-next-line no-eval
|
|
113
|
+
codeConfigProcessed.content = eval(codeConfig.content);
|
|
114
|
+
}
|
|
103
115
|
if (!codeDsl) {
|
|
104
116
|
// dsl中无代码块字段
|
|
105
117
|
codeDsl = {
|
|
106
|
-
[id]:
|
|
118
|
+
[id]: {
|
|
119
|
+
...codeConfigProcessed,
|
|
120
|
+
},
|
|
107
121
|
};
|
|
108
122
|
} else {
|
|
109
123
|
const existContent = codeDsl[id] || {};
|
|
@@ -111,7 +125,7 @@ class CodeBlock extends BaseService {
|
|
|
111
125
|
...codeDsl,
|
|
112
126
|
[id]: {
|
|
113
127
|
...existContent,
|
|
114
|
-
...
|
|
128
|
+
...codeConfigProcessed,
|
|
115
129
|
},
|
|
116
130
|
};
|
|
117
131
|
}
|
|
@@ -148,10 +162,10 @@ class CodeBlock extends BaseService {
|
|
|
148
162
|
/**
|
|
149
163
|
* 设置代码编辑面板展示状态及展示内容
|
|
150
164
|
* @param {boolean} status 是否展示代码编辑面板
|
|
151
|
-
* @param {
|
|
165
|
+
* @param {Id} id 代码块id
|
|
152
166
|
* @returns {void}
|
|
153
167
|
*/
|
|
154
|
-
public setCodeEditorContent(status: boolean, id:
|
|
168
|
+
public setCodeEditorContent(status: boolean, id: Id): void {
|
|
155
169
|
if (!id) return;
|
|
156
170
|
this.setId(id);
|
|
157
171
|
this.state.isShowCodeEditor = status;
|
|
@@ -161,7 +175,7 @@ class CodeBlock extends BaseService {
|
|
|
161
175
|
* 获取当前选中的代码块内容
|
|
162
176
|
* @returns {CodeBlockContent | null}
|
|
163
177
|
*/
|
|
164
|
-
public async getCurrentDsl() {
|
|
178
|
+
public async getCurrentDsl(): Promise<CodeBlockContent | null> {
|
|
165
179
|
return await this.getCodeContentById(this.state.id);
|
|
166
180
|
}
|
|
167
181
|
|
|
@@ -184,19 +198,19 @@ class CodeBlock extends BaseService {
|
|
|
184
198
|
|
|
185
199
|
/**
|
|
186
200
|
* 设置当前选中的代码块ID
|
|
187
|
-
* @param {
|
|
201
|
+
* @param {Id} id 代码块id
|
|
188
202
|
* @returns {void}
|
|
189
203
|
*/
|
|
190
|
-
public setId(id:
|
|
204
|
+
public setId(id: Id): void {
|
|
191
205
|
if (!id) return;
|
|
192
206
|
this.state.id = id;
|
|
193
207
|
}
|
|
194
208
|
|
|
195
209
|
/**
|
|
196
210
|
* 获取当前选中的代码块ID
|
|
197
|
-
* @returns {
|
|
211
|
+
* @returns {Id} id 代码块id
|
|
198
212
|
*/
|
|
199
|
-
public getId():
|
|
213
|
+
public getId(): Id {
|
|
200
214
|
return this.state.id;
|
|
201
215
|
}
|
|
202
216
|
|
|
@@ -235,98 +249,70 @@ class CodeBlock extends BaseService {
|
|
|
235
249
|
}
|
|
236
250
|
|
|
237
251
|
/**
|
|
238
|
-
*
|
|
239
|
-
* @
|
|
240
|
-
* @param {string[]} diffCodeIds 代码块id数组
|
|
241
|
-
* @param {CodeSelectOp} opFlag 操作类型
|
|
242
|
-
* @param {string} hook 代码块挂载hook名称
|
|
243
|
-
* @returns {void}
|
|
252
|
+
* 刷新绑定关系
|
|
253
|
+
* @returns {CodeRelation | null}
|
|
244
254
|
*/
|
|
245
|
-
public
|
|
246
|
-
const
|
|
247
|
-
if (!
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
} else if (opFlag === CodeSelectOp.ADD) {
|
|
262
|
-
try {
|
|
263
|
-
diffCodeIds.forEach((codeId) => {
|
|
264
|
-
const compsContent = codeDsl[codeId].comps;
|
|
265
|
-
const existHooks = compsContent?.[compId];
|
|
266
|
-
if (isEmpty(existHooks)) {
|
|
267
|
-
// comps属性不存在,或者comps为空:新增
|
|
268
|
-
codeDsl[codeId].comps = {
|
|
269
|
-
...(codeDsl[codeId].comps || {}),
|
|
270
|
-
[compId]: [hook],
|
|
271
|
-
};
|
|
272
|
-
} else {
|
|
273
|
-
// 往已有的关系中添加hook
|
|
274
|
-
existHooks?.push(hook);
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
} catch (e) {
|
|
278
|
-
error(e);
|
|
279
|
-
throw new Error('绑定代码块失败');
|
|
280
|
-
}
|
|
281
|
-
} else if (opFlag === CodeSelectOp.CHANGE) {
|
|
282
|
-
// 单选修改
|
|
283
|
-
forIn(codeDsl, (codeBlockContent, codeId) => {
|
|
284
|
-
if (codeId === diffCodeIds[0]) {
|
|
285
|
-
// 增加
|
|
286
|
-
codeBlockContent.comps = {
|
|
287
|
-
...(codeBlockContent?.comps || {}),
|
|
288
|
-
[compId]: [hook],
|
|
289
|
-
};
|
|
290
|
-
} else if (isEmpty(diffCodeIds) || codeId !== diffCodeIds[0]) {
|
|
291
|
-
// 清空或者移除之前的选项
|
|
292
|
-
const compHooks = codeBlockContent?.comps?.[compId];
|
|
293
|
-
// continue
|
|
294
|
-
if (!compHooks) return true;
|
|
295
|
-
const index = compHooks.findIndex((hookName) => hookName === hook);
|
|
296
|
-
if (index !== -1) {
|
|
297
|
-
compHooks.splice(index, 1);
|
|
298
|
-
// break
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
this.setCodeDsl(codeDsl);
|
|
255
|
+
public refreshCombineInfo(): CodeRelation | null {
|
|
256
|
+
const root = editorService.get<MApp | null>('root');
|
|
257
|
+
if (!root) return null;
|
|
258
|
+
const relations = {};
|
|
259
|
+
this.recurseMNode(root, relations);
|
|
260
|
+
this.state.relations = relations;
|
|
261
|
+
return this.state.relations;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 获取绑定关系
|
|
266
|
+
* @returns {CodeRelation}
|
|
267
|
+
*/
|
|
268
|
+
public getCombineInfo(): CodeRelation {
|
|
269
|
+
return this.state.relations;
|
|
305
270
|
}
|
|
306
271
|
|
|
307
272
|
/**
|
|
308
273
|
* 获取不可删除列表
|
|
309
|
-
* @returns {
|
|
274
|
+
* @returns {Id[]}
|
|
310
275
|
*/
|
|
311
|
-
public getUndeletableList():
|
|
276
|
+
public getUndeletableList(): Id[] {
|
|
312
277
|
return this.state.undeletableList;
|
|
313
278
|
}
|
|
314
279
|
|
|
315
280
|
/**
|
|
316
281
|
* 设置不可删除列表:为业务逻辑预留的不可删除的代码块列表,由业务逻辑维护(如代码块上线后不可删除)
|
|
317
|
-
* @param {
|
|
282
|
+
* @param {Id[]} codeIds 代码块id数组
|
|
318
283
|
* @returns {void}
|
|
319
284
|
*/
|
|
320
|
-
public async setUndeleteableList(codeIds:
|
|
285
|
+
public async setUndeleteableList(codeIds: Id[]): Promise<void> {
|
|
321
286
|
this.state.undeletableList = codeIds;
|
|
322
287
|
}
|
|
323
288
|
|
|
289
|
+
/**
|
|
290
|
+
* 设置代码草稿
|
|
291
|
+
*/
|
|
292
|
+
public setCodeDraft(codeId: Id, content: string): void {
|
|
293
|
+
globalThis.localStorage.setItem(`${CODE_DRAFT_STORAGE_KEY}_${codeId}`, content);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* 获取代码草稿
|
|
298
|
+
*/
|
|
299
|
+
public getCodeDraft(codeId: Id): string | null {
|
|
300
|
+
return globalThis.localStorage.getItem(`${CODE_DRAFT_STORAGE_KEY}_${codeId}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* 删除代码草稿
|
|
305
|
+
*/
|
|
306
|
+
public removeCodeDraft(codeId: Id): void {
|
|
307
|
+
globalThis.localStorage.removeItem(`${CODE_DRAFT_STORAGE_KEY}_${codeId}`);
|
|
308
|
+
}
|
|
309
|
+
|
|
324
310
|
/**
|
|
325
311
|
* 在dsl数据源中删除指定id的代码块
|
|
326
|
-
* @param {
|
|
312
|
+
* @param {Id[]} codeIds 需要删除的代码块id数组
|
|
327
313
|
* @returns {CodeBlockDSL} 删除后的code dsl
|
|
328
314
|
*/
|
|
329
|
-
public async deleteCodeDslByIds(codeIds:
|
|
315
|
+
public async deleteCodeDslByIds(codeIds: Id[]): Promise<CodeBlockDSL> {
|
|
330
316
|
const currentDsl = await this.getCodeDsl();
|
|
331
317
|
const newDsl = omit(currentDsl, codeIds);
|
|
332
318
|
await this.setCodeDsl(newDsl);
|
|
@@ -335,9 +321,9 @@ class CodeBlock extends BaseService {
|
|
|
335
321
|
|
|
336
322
|
/**
|
|
337
323
|
* 生成代码块唯一id
|
|
338
|
-
* @returns {
|
|
324
|
+
* @returns {Id} 代码块唯一id
|
|
339
325
|
*/
|
|
340
|
-
public async getUniqueId(): Promise<
|
|
326
|
+
public async getUniqueId(): Promise<Id> {
|
|
341
327
|
const newId = `code_${Math.random().toString(10).substring(2).substring(0, 4)}`;
|
|
342
328
|
// 判断是否重复
|
|
343
329
|
const dsl = await this.getCodeDsl();
|
|
@@ -346,46 +332,19 @@ class CodeBlock extends BaseService {
|
|
|
346
332
|
return await this.getUniqueId();
|
|
347
333
|
}
|
|
348
334
|
|
|
349
|
-
/**
|
|
350
|
-
* 一对一解除绑定关系 功能隐藏,暂时注释
|
|
351
|
-
* @param {string} compId 组件id
|
|
352
|
-
* @param {string} codeId 代码块id
|
|
353
|
-
* @param {string[]} codeHooks 代码块挂载hook名称
|
|
354
|
-
* @returns {boolean} 结果
|
|
355
|
-
*/
|
|
356
|
-
// public async unbind(compId: Id, codeId: string, codeHooks: string[]): Promise<boolean> {
|
|
357
|
-
// const nodeInfo = editorService.getNodeById(compId);
|
|
358
|
-
// if (!nodeInfo) return false;
|
|
359
|
-
// // 更新node节点信息
|
|
360
|
-
// codeHooks.forEach((hook) => {
|
|
361
|
-
// if (!isEmpty(nodeInfo[hook])) {
|
|
362
|
-
// const newHookInfo = nodeInfo[hook].filter((item: string) => item !== codeId);
|
|
363
|
-
// nodeInfo[hook] = newHookInfo;
|
|
364
|
-
// editorService.update(nodeInfo);
|
|
365
|
-
// }
|
|
366
|
-
// });
|
|
367
|
-
// // 更新绑定关系
|
|
368
|
-
// const oldRelation = await this.getCompRelation();
|
|
369
|
-
// const oldCodeIds = oldRelation[compId];
|
|
370
|
-
// // 不能直接splice修改原数组,会导致绑定关系更新错乱
|
|
371
|
-
// const newCodeIds = oldCodeIds.filter((item) => item !== codeId);
|
|
372
|
-
// this.setCompRelation(compId, newCodeIds);
|
|
373
|
-
// return true;
|
|
374
|
-
// }
|
|
375
|
-
|
|
376
335
|
/**
|
|
377
336
|
* 通过组件id解除绑定关系(删除组件)
|
|
378
337
|
* @param {MNode} compId 组件节点
|
|
379
338
|
* @returns void
|
|
380
339
|
*/
|
|
381
|
-
public async deleteCompsInRelation(node: MNode) {
|
|
340
|
+
public async deleteCompsInRelation(node: MNode): Promise<void> {
|
|
382
341
|
const codeDsl = cloneDeep(await this.getCodeDsl());
|
|
383
342
|
if (!codeDsl) return;
|
|
384
|
-
this.
|
|
343
|
+
this.refreshRelationDeep(node, codeDsl);
|
|
385
344
|
this.setCodeDsl(codeDsl);
|
|
386
345
|
}
|
|
387
346
|
|
|
388
|
-
public
|
|
347
|
+
public resetState() {
|
|
389
348
|
this.state.isShowCodeEditor = false;
|
|
390
349
|
this.state.codeDsl = null;
|
|
391
350
|
this.state.id = '';
|
|
@@ -395,8 +354,19 @@ class CodeBlock extends BaseService {
|
|
|
395
354
|
this.state.undeletableList = [];
|
|
396
355
|
}
|
|
397
356
|
|
|
398
|
-
|
|
399
|
-
|
|
357
|
+
public destroy(): void {
|
|
358
|
+
this.resetState();
|
|
359
|
+
this.removeAllListeners();
|
|
360
|
+
this.removeAllPlugins();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* 删除组件时 如果是容器 需要遍历删除其包含节点的绑定信息
|
|
365
|
+
* @param {MNode} node 节点信息
|
|
366
|
+
* @param {CodeBlockDSL} codeDsl 代码块
|
|
367
|
+
* @returns void
|
|
368
|
+
*/
|
|
369
|
+
private refreshRelationDeep(node: MNode, codeDsl: CodeBlockDSL): void {
|
|
400
370
|
if (!node.id) return;
|
|
401
371
|
forIn(codeDsl, (codeBlockContent) => {
|
|
402
372
|
const compsContent = codeBlockContent.comps || {};
|
|
@@ -404,7 +374,36 @@ class CodeBlock extends BaseService {
|
|
|
404
374
|
});
|
|
405
375
|
if (!isEmpty(node.items)) {
|
|
406
376
|
node.items.forEach((item: MNode) => {
|
|
407
|
-
this.
|
|
377
|
+
this.refreshRelationDeep(item, codeDsl);
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* 递归遍历dsl中挂载了代码块的节点,并更新绑定关系数据
|
|
384
|
+
* @param {MContainer} node 节点信息
|
|
385
|
+
* @returns void
|
|
386
|
+
*/
|
|
387
|
+
private recurseMNode(node: MNode, relations: CodeRelation): void {
|
|
388
|
+
forIn(node, (value, key) => {
|
|
389
|
+
if (value?.hookType === HookType.CODE && !isEmpty(value.hookData)) {
|
|
390
|
+
value.hookData.forEach((relationItem: HookData) => {
|
|
391
|
+
// continue
|
|
392
|
+
if (!relationItem.codeId) return;
|
|
393
|
+
if (!relations[relationItem.codeId]) {
|
|
394
|
+
relations[relationItem.codeId] = {};
|
|
395
|
+
}
|
|
396
|
+
const codeItem = relations[relationItem.codeId];
|
|
397
|
+
if (isEmpty(codeItem[node.id])) {
|
|
398
|
+
codeItem[node.id] = [];
|
|
399
|
+
}
|
|
400
|
+
codeItem[node.id].push(key);
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
if (!isEmpty(node.items)) {
|
|
405
|
+
node.items.forEach((item: MNode) => {
|
|
406
|
+
this.recurseMNode(item, relations);
|
|
408
407
|
});
|
|
409
408
|
}
|
|
410
409
|
}
|
|
@@ -42,9 +42,14 @@ class ComponentList extends BaseService {
|
|
|
42
42
|
return this.state.list;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
public
|
|
45
|
+
public resetState() {
|
|
46
46
|
this.state.list = [];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public destroy() {
|
|
50
|
+
this.resetState();
|
|
47
51
|
this.removeAllListeners();
|
|
52
|
+
this.removeAllPlugins();
|
|
48
53
|
}
|
|
49
54
|
}
|
|
50
55
|
|
package/src/services/editor.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { reactive, toRaw } from 'vue';
|
|
20
|
-
import { cloneDeep, mergeWith, uniq } from 'lodash-es';
|
|
20
|
+
import { cloneDeep, isObject, mergeWith, uniq } from 'lodash-es';
|
|
21
21
|
|
|
22
22
|
import type { CodeBlockDSL, Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
23
23
|
import { NodeType } from '@tmagic/schema';
|
|
@@ -25,9 +25,9 @@ import StageCore from '@tmagic/stage';
|
|
|
25
25
|
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
|
26
26
|
|
|
27
27
|
import codeBlockService from '../services/codeBlock';
|
|
28
|
-
import historyService
|
|
28
|
+
import historyService from '../services/history';
|
|
29
29
|
import storageService, { Protocol } from '../services/storage';
|
|
30
|
-
import type { AddMNode, EditorNodeInfo, PastePosition, StoreState } from '../type';
|
|
30
|
+
import type { AddMNode, EditorNodeInfo, PastePosition, StepValue, StoreState } from '../type';
|
|
31
31
|
import { LayerOffset, Layout } from '../type';
|
|
32
32
|
import {
|
|
33
33
|
change2Fixed,
|
|
@@ -73,7 +73,7 @@ class Editor extends BaseService {
|
|
|
73
73
|
'copy',
|
|
74
74
|
'paste',
|
|
75
75
|
'doPaste',
|
|
76
|
-
'
|
|
76
|
+
'doAlignCenter',
|
|
77
77
|
'alignCenter',
|
|
78
78
|
'moveLayer',
|
|
79
79
|
'moveToContainer',
|
|
@@ -91,11 +91,11 @@ class Editor extends BaseService {
|
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
93
|
* 设置当前指点节点配置
|
|
94
|
-
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes'
|
|
94
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength'
|
|
95
95
|
* @param value MNode
|
|
96
|
-
* @returns MNode
|
|
97
96
|
*/
|
|
98
97
|
public set<T = MNode>(name: keyof StoreState, value: T) {
|
|
98
|
+
const preValue = this.state[name];
|
|
99
99
|
this.state[name] = value as any;
|
|
100
100
|
// set nodes时将node设置为nodes第一个元素
|
|
101
101
|
if (name === 'nodes') {
|
|
@@ -103,13 +103,13 @@ class Editor extends BaseService {
|
|
|
103
103
|
}
|
|
104
104
|
if (name === 'root') {
|
|
105
105
|
this.state.pageLength = (value as unknown as MApp)?.items?.length || 0;
|
|
106
|
-
this.emit('root-change', value);
|
|
106
|
+
this.emit('root-change', value, preValue);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
111
|
* 获取当前指点节点配置
|
|
112
|
-
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes'
|
|
112
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength'
|
|
113
113
|
* @returns MNode
|
|
114
114
|
*/
|
|
115
115
|
public get<T = MNode>(name: keyof StoreState): T {
|
|
@@ -208,7 +208,7 @@ class Editor extends BaseService {
|
|
|
208
208
|
if (page) {
|
|
209
209
|
historyService.changePage(toRaw(page));
|
|
210
210
|
} else {
|
|
211
|
-
historyService.
|
|
211
|
+
historyService.resetState();
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
if (node?.id) {
|
|
@@ -353,6 +353,9 @@ class Editor extends BaseService {
|
|
|
353
353
|
|
|
354
354
|
const newNodes = await Promise.all(
|
|
355
355
|
addNodes.map((node) => {
|
|
356
|
+
if (isPage(node)) {
|
|
357
|
+
return this.doAdd(node, this.get('root'));
|
|
358
|
+
}
|
|
356
359
|
const parentNode = parent && typeof parent !== 'function' ? parent : getAddParent(node);
|
|
357
360
|
if (!parentNode) throw new Error('未找到父元素');
|
|
358
361
|
return this.doAdd(node, parentNode);
|
|
@@ -375,7 +378,9 @@ class Editor extends BaseService {
|
|
|
375
378
|
}
|
|
376
379
|
}
|
|
377
380
|
|
|
378
|
-
|
|
381
|
+
if (!isPage(newNodes[0])) {
|
|
382
|
+
this.pushHistoryState();
|
|
383
|
+
}
|
|
379
384
|
|
|
380
385
|
this.emit('add', newNodes);
|
|
381
386
|
|
|
@@ -430,15 +435,16 @@ class Editor extends BaseService {
|
|
|
430
435
|
/**
|
|
431
436
|
* 删除组件
|
|
432
437
|
* @param {Object} node
|
|
433
|
-
* @return {Object} 删除的组件配置
|
|
434
438
|
*/
|
|
435
439
|
public async remove(nodeOrNodeList: MNode | MNode[]): Promise<void> {
|
|
436
440
|
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
437
441
|
|
|
438
442
|
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
439
443
|
|
|
440
|
-
|
|
441
|
-
|
|
444
|
+
if (!isPage(nodes[0])) {
|
|
445
|
+
// 更新历史记录
|
|
446
|
+
this.pushHistoryState();
|
|
447
|
+
}
|
|
442
448
|
|
|
443
449
|
this.emit('remove', nodes);
|
|
444
450
|
}
|
|
@@ -455,6 +461,10 @@ class Editor extends BaseService {
|
|
|
455
461
|
let newConfig = await this.toggleFixedPosition(toRaw(config), node, this.get<MApp>('root'));
|
|
456
462
|
|
|
457
463
|
newConfig = mergeWith(cloneDeep(node), newConfig, (objValue, srcValue) => {
|
|
464
|
+
if (isObject(srcValue) && Array.isArray(objValue)) {
|
|
465
|
+
// 原来的配置是数组,新的配置是对象,则直接使用新的值
|
|
466
|
+
return srcValue;
|
|
467
|
+
}
|
|
458
468
|
if (Array.isArray(srcValue)) {
|
|
459
469
|
return srcValue;
|
|
460
470
|
}
|
|
@@ -517,7 +527,7 @@ class Editor extends BaseService {
|
|
|
517
527
|
this.pushHistoryState();
|
|
518
528
|
|
|
519
529
|
this.emit('update', newNodes);
|
|
520
|
-
|
|
530
|
+
codeBlockService.refreshCombineInfo();
|
|
521
531
|
return Array.isArray(config) ? newNodes : newNodes[0];
|
|
522
532
|
}
|
|
523
533
|
|
|
@@ -571,9 +581,20 @@ class Editor extends BaseService {
|
|
|
571
581
|
|
|
572
582
|
if (!Array.isArray(config)) return;
|
|
573
583
|
|
|
584
|
+
const node = this.get<MNode>('node');
|
|
585
|
+
|
|
586
|
+
let parent: MContainer | undefined = undefined;
|
|
587
|
+
// 粘贴的组件为当前选中组件的副本时,则添加到当前选中组件的父组件中
|
|
588
|
+
if (config.length === 1 && config[0].id === node.id) {
|
|
589
|
+
parent = this.get<MContainer>('parent');
|
|
590
|
+
if (parent.type === NodeType.ROOT) {
|
|
591
|
+
parent = this.get<MPage>('page');
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
574
595
|
const pasteConfigs = await this.doPaste(config, position);
|
|
575
596
|
|
|
576
|
-
return this.add(pasteConfigs);
|
|
597
|
+
return this.add(pasteConfigs, parent);
|
|
577
598
|
}
|
|
578
599
|
|
|
579
600
|
public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
|
|
@@ -623,7 +644,11 @@ class Editor extends BaseService {
|
|
|
623
644
|
|
|
624
645
|
const newNode = await this.update(newNodes);
|
|
625
646
|
|
|
626
|
-
|
|
647
|
+
if (newNodes.length > 1) {
|
|
648
|
+
await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
649
|
+
} else {
|
|
650
|
+
await stage?.select(newNodes[0].id);
|
|
651
|
+
}
|
|
627
652
|
|
|
628
653
|
return newNode;
|
|
629
654
|
}
|
|
@@ -749,8 +774,7 @@ class Editor extends BaseService {
|
|
|
749
774
|
});
|
|
750
775
|
}
|
|
751
776
|
|
|
752
|
-
public
|
|
753
|
-
this.removeAllListeners();
|
|
777
|
+
public resetState() {
|
|
754
778
|
this.set('root', null);
|
|
755
779
|
this.set('node', null);
|
|
756
780
|
this.set('nodes', []);
|
|
@@ -762,6 +786,12 @@ class Editor extends BaseService {
|
|
|
762
786
|
this.set('pageLength', new Map());
|
|
763
787
|
}
|
|
764
788
|
|
|
789
|
+
public destroy() {
|
|
790
|
+
this.removeAllListeners();
|
|
791
|
+
this.resetState();
|
|
792
|
+
this.removeAllPlugins();
|
|
793
|
+
}
|
|
794
|
+
|
|
765
795
|
public resetModifiedNodeId() {
|
|
766
796
|
this.get<Map<Id, Id>>('modifiedNodeIds').clear();
|
|
767
797
|
}
|
|
@@ -776,6 +806,12 @@ class Editor extends BaseService {
|
|
|
776
806
|
return root.codeBlocks || null;
|
|
777
807
|
}
|
|
778
808
|
|
|
809
|
+
public getCodeDslSync(): CodeBlockDSL | null {
|
|
810
|
+
const root = this.get<MApp | null>('root');
|
|
811
|
+
if (!root) return null;
|
|
812
|
+
return root.codeBlocks || null;
|
|
813
|
+
}
|
|
814
|
+
|
|
779
815
|
/**
|
|
780
816
|
* 设置代码块到dsl的codeBlocks字段
|
|
781
817
|
* @param {CodeBlockDSL} codeDsl 代码DSL
|
package/src/services/events.ts
CHANGED
|
@@ -76,10 +76,15 @@ class Events extends BaseService {
|
|
|
76
76
|
return cloneDeep(methodMap[type] || DEFAULT_METHODS);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
public
|
|
79
|
+
public resetState() {
|
|
80
80
|
eventMap = reactive({});
|
|
81
81
|
methodMap = reactive({});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public destroy() {
|
|
85
|
+
this.resetState();
|
|
82
86
|
this.removeAllListeners();
|
|
87
|
+
this.removeAllPlugins();
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
90
|
|