@tmagic/editor 1.8.0-beta.0 → 1.8.0-beta.2
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/Editor.vue_vue_type_script_setup_true_lang.js +11 -2
- package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +18 -110
- package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +6 -0
- package/dist/es/components/CompareForm.js +5 -0
- package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +167 -0
- package/dist/es/fields/Code.vue_vue_type_script_setup_true_lang.js +19 -3
- package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +18 -2
- package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +37 -6
- package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/es/fields/DataSourceFieldSelect/Index.vue_vue_type_script_setup_true_lang.js +12 -3
- package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +14 -6
- package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +3 -1
- package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +15 -7
- package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +14 -6
- package/dist/es/fields/DataSourceSelect.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +58 -11
- package/dist/es/fields/KeyValue.vue_vue_type_script_setup_true_lang.js +11 -6
- package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +8 -2
- package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +10 -2
- package/dist/es/fields/StyleSetter/components/Box.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +10 -2
- package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +16 -3
- package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +10 -2
- package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +14 -2
- package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +10 -2
- package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +10 -2
- package/dist/es/fields/UISelect.vue_vue_type_script_setup_true_lang.js +8 -5
- package/dist/es/hooks/use-code-block-edit.js +2 -2
- package/dist/es/hooks/use-stage.js +15 -7
- package/dist/es/index.js +3 -1
- package/dist/es/initService.js +6 -6
- package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +12 -7
- package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +8 -0
- package/dist/es/layouts/history-list/Bucket.js +5 -0
- package/dist/es/layouts/history-list/Bucket.vue_vue_type_script_setup_true_lang.js +84 -0
- package/dist/es/layouts/history-list/CodeBlockTab.js +5 -0
- package/dist/es/layouts/history-list/CodeBlockTab.vue_vue_type_script_setup_true_lang.js +62 -0
- package/dist/es/layouts/history-list/DataSourceTab.js +5 -0
- package/dist/es/layouts/history-list/DataSourceTab.vue_vue_type_script_setup_true_lang.js +62 -0
- package/dist/es/layouts/history-list/GroupRow.js +5 -0
- package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +180 -0
- package/dist/es/layouts/history-list/HistoryDiffDialog.js +5 -0
- package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +195 -0
- package/dist/es/layouts/history-list/HistoryListPanel.js +5 -0
- package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +270 -0
- package/dist/es/layouts/history-list/InitialRow.js +5 -0
- package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +48 -0
- package/dist/es/layouts/history-list/PageTab.js +5 -0
- package/dist/es/layouts/history-list/PageTab.vue_vue_type_script_setup_true_lang.js +99 -0
- package/dist/es/layouts/history-list/composables.js +154 -0
- package/dist/es/layouts/sidebar/layer/use-node-status.js +38 -4
- package/dist/es/services/BaseService.js +31 -68
- package/dist/es/services/codeBlock.js +205 -8
- package/dist/es/services/componentList.js +2 -2
- package/dist/es/services/dataSource.js +217 -8
- package/dist/es/services/dep.js +21 -9
- package/dist/es/services/editor.js +350 -160
- package/dist/es/services/events.js +2 -2
- package/dist/es/services/history.js +407 -12
- package/dist/es/services/keybinding.js +2 -2
- package/dist/es/services/props.js +8 -8
- package/dist/es/services/stageOverlay.js +2 -2
- package/dist/es/services/storage.js +2 -2
- package/dist/es/services/ui.js +2 -2
- package/dist/es/style.css +347 -1
- package/dist/es/utils/code-block.js +122 -0
- package/dist/es/utils/content-menu.js +4 -5
- package/dist/es/utils/dep/worker.js +1 -1
- package/dist/es/utils/editor.js +3 -3
- package/dist/es/utils/undo-redo.js +20 -0
- package/dist/style.css +347 -1
- package/dist/tmagic-editor.umd.cjs +3273 -766
- package/package.json +7 -7
- package/src/Editor.vue +7 -0
- package/src/components/CodeBlockEditor.vue +20 -109
- package/src/components/CodeParams.vue +6 -0
- package/src/components/CompareForm.vue +225 -0
- package/src/editorProps.ts +2 -0
- package/src/fields/Code.vue +19 -3
- package/src/fields/CodeSelect.vue +17 -1
- package/src/fields/CodeSelectCol.vue +30 -2
- package/src/fields/DataSourceFieldSelect/FieldSelect.vue +7 -1
- package/src/fields/DataSourceFieldSelect/Index.vue +9 -2
- package/src/fields/DataSourceFields.vue +12 -3
- package/src/fields/DataSourceMethodSelect.vue +4 -1
- package/src/fields/DataSourceMethods.vue +14 -4
- package/src/fields/DataSourceMocks.vue +13 -3
- package/src/fields/DataSourceSelect.vue +4 -1
- package/src/fields/EventSelect.vue +57 -8
- package/src/fields/KeyValue.vue +17 -4
- package/src/fields/StyleSetter/Index.vue +6 -0
- package/src/fields/StyleSetter/components/Border.vue +15 -1
- package/src/fields/StyleSetter/components/Box.vue +2 -0
- package/src/fields/StyleSetter/pro/Background.vue +15 -1
- package/src/fields/StyleSetter/pro/Border.vue +24 -2
- package/src/fields/StyleSetter/pro/Font.vue +15 -1
- package/src/fields/StyleSetter/pro/Layout.vue +17 -1
- package/src/fields/StyleSetter/pro/Position.vue +15 -1
- package/src/fields/StyleSetter/pro/Transform.vue +15 -1
- package/src/fields/UISelect.vue +5 -2
- package/src/hooks/use-code-block-edit.ts +5 -2
- package/src/hooks/use-stage.ts +23 -7
- package/src/index.ts +1 -0
- package/src/layouts/CodeEditor.vue +15 -0
- package/src/layouts/Framework.vue +10 -5
- package/src/layouts/NavMenu.vue +9 -0
- package/src/layouts/history-list/Bucket.vue +99 -0
- package/src/layouts/history-list/CodeBlockTab.vue +61 -0
- package/src/layouts/history-list/DataSourceTab.vue +61 -0
- package/src/layouts/history-list/GroupRow.vue +207 -0
- package/src/layouts/history-list/HistoryDiffDialog.vue +212 -0
- package/src/layouts/history-list/HistoryListPanel.vue +271 -0
- package/src/layouts/history-list/InitialRow.vue +41 -0
- package/src/layouts/history-list/PageTab.vue +94 -0
- package/src/layouts/history-list/composables.ts +195 -0
- package/src/layouts/sidebar/layer/use-node-status.ts +64 -12
- package/src/services/BaseService.ts +35 -86
- package/src/services/codeBlock.ts +256 -5
- package/src/services/dataSource.ts +257 -6
- package/src/services/dep.ts +32 -9
- package/src/services/editor.ts +454 -171
- package/src/services/history.ts +452 -8
- package/src/services/props.ts +2 -2
- package/src/theme/history-list-panel.scss +423 -0
- package/src/theme/theme.scss +1 -0
- package/src/type.ts +179 -6
- package/src/utils/code-block.ts +150 -0
- package/src/utils/content-menu.ts +8 -5
- package/src/utils/dep/worker.ts +5 -3
- package/src/utils/editor.ts +4 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/undo-redo.ts +23 -0
- package/types/index.d.ts +2107 -810
- package/dist/es/utils/compose.js +0 -44
- package/dist/es/utils/editor-history.js +0 -100
- package/src/utils/compose.ts +0 -52
- package/src/utils/editor-history.ts +0 -138
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseService from "./BaseService.js";
|
|
2
2
|
import { toLine } from "@tmagic/utils";
|
|
3
3
|
import { reactive } from "vue";
|
|
4
4
|
import { cloneDeep } from "lodash-es";
|
|
@@ -14,7 +14,7 @@ var canUsePluginMethods = {
|
|
|
14
14
|
};
|
|
15
15
|
var eventMap = reactive({});
|
|
16
16
|
var methodMap = reactive({});
|
|
17
|
-
var Events = class extends
|
|
17
|
+
var Events = class extends BaseService {
|
|
18
18
|
constructor() {
|
|
19
19
|
super([...canUsePluginMethods.async.map((methodName) => ({
|
|
20
20
|
name: methodName,
|
|
@@ -1,13 +1,179 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseService from "./BaseService.js";
|
|
2
2
|
import { UndoRedo } from "../utils/undo-redo.js";
|
|
3
3
|
import { reactive } from "vue";
|
|
4
|
-
|
|
5
|
-
var
|
|
4
|
+
import { cloneDeep } from "lodash-es";
|
|
5
|
+
var history_default = new class History extends BaseService {
|
|
6
|
+
/**
|
|
7
|
+
* 把单个代码块栈拆成若干 group:
|
|
8
|
+
* - 把"新增/删除"独立成组(语义上属于一次性事件,不应与 update 合并);
|
|
9
|
+
* - 连续 'update' 合并到同一组,组内 steps 顺序就是发生顺序。
|
|
10
|
+
*/
|
|
11
|
+
static mergeCodeBlockSteps(codeBlockId, list, cursor) {
|
|
12
|
+
const groups = [];
|
|
13
|
+
let current = null;
|
|
14
|
+
const currentIndex = cursor - 1;
|
|
15
|
+
list.forEach((step, index) => {
|
|
16
|
+
const opType = History.detectOpType(step.oldContent, step.newContent);
|
|
17
|
+
const applied = index < cursor;
|
|
18
|
+
const isCurrent = index === currentIndex;
|
|
19
|
+
if (opType === "update" && current?.opType === "update") {
|
|
20
|
+
current.steps.push({
|
|
21
|
+
step,
|
|
22
|
+
index,
|
|
23
|
+
applied,
|
|
24
|
+
isCurrent
|
|
25
|
+
});
|
|
26
|
+
current.applied = applied;
|
|
27
|
+
if (isCurrent) current.isCurrent = true;
|
|
28
|
+
} else {
|
|
29
|
+
current = {
|
|
30
|
+
kind: "code-block",
|
|
31
|
+
id: codeBlockId,
|
|
32
|
+
opType,
|
|
33
|
+
steps: [{
|
|
34
|
+
step,
|
|
35
|
+
index,
|
|
36
|
+
applied,
|
|
37
|
+
isCurrent
|
|
38
|
+
}],
|
|
39
|
+
applied,
|
|
40
|
+
isCurrent
|
|
41
|
+
};
|
|
42
|
+
groups.push(current);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
return groups;
|
|
46
|
+
}
|
|
47
|
+
static mergeDataSourceSteps(dataSourceId, list, cursor) {
|
|
48
|
+
const groups = [];
|
|
49
|
+
let current = null;
|
|
50
|
+
const currentIndex = cursor - 1;
|
|
51
|
+
list.forEach((step, index) => {
|
|
52
|
+
const opType = History.detectOpType(step.oldSchema, step.newSchema);
|
|
53
|
+
const applied = index < cursor;
|
|
54
|
+
const isCurrent = index === currentIndex;
|
|
55
|
+
if (opType === "update" && current?.opType === "update") {
|
|
56
|
+
current.steps.push({
|
|
57
|
+
step,
|
|
58
|
+
index,
|
|
59
|
+
applied,
|
|
60
|
+
isCurrent
|
|
61
|
+
});
|
|
62
|
+
current.applied = applied;
|
|
63
|
+
if (isCurrent) current.isCurrent = true;
|
|
64
|
+
} else {
|
|
65
|
+
current = {
|
|
66
|
+
kind: "data-source",
|
|
67
|
+
id: dataSourceId,
|
|
68
|
+
opType,
|
|
69
|
+
steps: [{
|
|
70
|
+
step,
|
|
71
|
+
index,
|
|
72
|
+
applied,
|
|
73
|
+
isCurrent
|
|
74
|
+
}],
|
|
75
|
+
applied,
|
|
76
|
+
isCurrent
|
|
77
|
+
};
|
|
78
|
+
groups.push(current);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return groups;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 根据 old/new 是否为 null 推断 opType(与 push 时的约定一致)。
|
|
85
|
+
*/
|
|
86
|
+
static detectOpType(oldVal, newVal) {
|
|
87
|
+
if (oldVal === null && newVal !== null) return "add";
|
|
88
|
+
if (oldVal !== null && newVal === null) return "remove";
|
|
89
|
+
return "update";
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 把页面栈拆成若干 group:
|
|
93
|
+
* - 单节点的 'update' 按 targetId 与相邻同 targetId 的 update 合并到一个 group;
|
|
94
|
+
* - 'add' / 'remove' 始终独立成组(语义上是结构变更,不应被收纳进单节点修改组);
|
|
95
|
+
* - 多节点 'update'(如批量改属性)也独立成组(无明确单一目标,避免误合并)。
|
|
96
|
+
*/
|
|
97
|
+
static mergePageSteps(pageId, list, cursor) {
|
|
98
|
+
const groups = [];
|
|
99
|
+
let current = null;
|
|
100
|
+
const currentIndex = cursor - 1;
|
|
101
|
+
list.forEach((step, index) => {
|
|
102
|
+
const applied = index < cursor;
|
|
103
|
+
const isCurrent = index === currentIndex;
|
|
104
|
+
const targetId = History.detectPageTargetId(step);
|
|
105
|
+
const targetName = History.detectPageTargetName(step);
|
|
106
|
+
const entry = {
|
|
107
|
+
step,
|
|
108
|
+
index,
|
|
109
|
+
applied,
|
|
110
|
+
isCurrent
|
|
111
|
+
};
|
|
112
|
+
const mergeable = step.opType === "update" && targetId !== void 0;
|
|
113
|
+
if (mergeable && current?.opType === "update" && current.targetId === targetId) {
|
|
114
|
+
current.steps.push(entry);
|
|
115
|
+
current.applied = applied;
|
|
116
|
+
if (isCurrent) current.isCurrent = true;
|
|
117
|
+
if (targetName) current.targetName = targetName;
|
|
118
|
+
} else {
|
|
119
|
+
current = {
|
|
120
|
+
kind: "page",
|
|
121
|
+
pageId,
|
|
122
|
+
opType: step.opType,
|
|
123
|
+
targetId: mergeable ? targetId : void 0,
|
|
124
|
+
targetName,
|
|
125
|
+
steps: [entry],
|
|
126
|
+
applied,
|
|
127
|
+
isCurrent
|
|
128
|
+
};
|
|
129
|
+
groups.push(current);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return groups;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 解析 StepValue 中的"目标节点 id"用于合并:
|
|
136
|
+
* - 单节点 update:取唯一一项 updatedItems 的节点 id;
|
|
137
|
+
* - 其它情形(多节点 update / add / remove):返回 undefined,表示不参与合并。
|
|
138
|
+
*/
|
|
139
|
+
static detectPageTargetId(step) {
|
|
140
|
+
if (step.opType !== "update") return void 0;
|
|
141
|
+
const items = step.updatedItems;
|
|
142
|
+
if (items?.length !== 1) return void 0;
|
|
143
|
+
return items[0].newNode?.id ?? items[0].oldNode?.id;
|
|
144
|
+
}
|
|
145
|
+
/** 解析 StepValue 中的目标节点可读名(用于 UI 展示)。 */
|
|
146
|
+
static detectPageTargetName(step) {
|
|
147
|
+
if (step.opType === "update") {
|
|
148
|
+
const items = step.updatedItems;
|
|
149
|
+
if (items?.length === 1) {
|
|
150
|
+
const node = items[0].newNode || items[0].oldNode;
|
|
151
|
+
return node?.name || node?.type || (node?.id !== void 0 ? `${node.id}` : void 0);
|
|
152
|
+
}
|
|
153
|
+
return items?.length ? `${items.length} 个节点` : void 0;
|
|
154
|
+
}
|
|
155
|
+
if (step.opType === "add") {
|
|
156
|
+
if (step.nodes?.length === 1) {
|
|
157
|
+
const n = step.nodes[0];
|
|
158
|
+
return n.name || n.type || `${n.id}`;
|
|
159
|
+
}
|
|
160
|
+
return step.nodes?.length ? `${step.nodes.length} 个节点` : void 0;
|
|
161
|
+
}
|
|
162
|
+
if (step.opType === "remove") {
|
|
163
|
+
if (step.removedItems?.length === 1) {
|
|
164
|
+
const n = step.removedItems[0].node;
|
|
165
|
+
return n.name || n.type || `${n.id}`;
|
|
166
|
+
}
|
|
167
|
+
return step.removedItems?.length ? `${step.removedItems.length} 个节点` : void 0;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
6
170
|
state = reactive({
|
|
7
171
|
pageSteps: {},
|
|
8
172
|
pageId: void 0,
|
|
9
173
|
canRedo: false,
|
|
10
|
-
canUndo: false
|
|
174
|
+
canUndo: false,
|
|
175
|
+
codeBlockState: {},
|
|
176
|
+
dataSourceState: {}
|
|
11
177
|
});
|
|
12
178
|
constructor() {
|
|
13
179
|
super([]);
|
|
@@ -15,6 +181,8 @@ var History = class extends BaseService_default {
|
|
|
15
181
|
}
|
|
16
182
|
reset() {
|
|
17
183
|
this.state.pageSteps = {};
|
|
184
|
+
this.state.codeBlockState = {};
|
|
185
|
+
this.state.dataSourceState = {};
|
|
18
186
|
this.resetPage();
|
|
19
187
|
}
|
|
20
188
|
resetPage() {
|
|
@@ -34,14 +202,109 @@ var History = class extends BaseService_default {
|
|
|
34
202
|
this.state.pageSteps = {};
|
|
35
203
|
this.state.canRedo = false;
|
|
36
204
|
this.state.canUndo = false;
|
|
205
|
+
this.state.codeBlockState = {};
|
|
206
|
+
this.state.dataSourceState = {};
|
|
37
207
|
}
|
|
38
|
-
|
|
39
|
-
|
|
208
|
+
/**
|
|
209
|
+
* 把一条步骤推入指定页面的栈;不指定 pageId 时落到当前活动页。
|
|
210
|
+
*
|
|
211
|
+
* 跨页操作(例如 `moveToContainer` 把节点搬到其它页)必须显式传入 `pageId`,
|
|
212
|
+
* 否则会把记录错误地落到操作发起页 / 当前激活页,破坏目标页 / 源页的撤销栈语义。
|
|
213
|
+
*/
|
|
214
|
+
push(state, pageId) {
|
|
215
|
+
const undoRedo = this.getUndoRedo(pageId);
|
|
40
216
|
if (!undoRedo) return null;
|
|
41
217
|
undoRedo.pushElement(state);
|
|
42
|
-
this.emit("change", state);
|
|
218
|
+
if (pageId === void 0 || `${pageId}` === `${this.state.pageId}`) this.emit("change", state);
|
|
43
219
|
return state;
|
|
44
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* 推入一条代码块变更记录(与页面/节点完全无关),按 `codeBlockId` 维度独立一份 UndoRedo 栈。
|
|
223
|
+
*
|
|
224
|
+
* - 新增:oldContent = null,newContent = 新内容
|
|
225
|
+
* - 更新:oldContent / newContent 都为对应内容
|
|
226
|
+
* - 删除:newContent = null,oldContent = 删除前内容
|
|
227
|
+
* - `changeRecords` 来自 form 端,撤销/重做时若有则按 propPath 局部覆盖;缺省才退化为整内容替换。
|
|
228
|
+
* - 不直接驱动 codeBlockService,调用方负责实际写回。
|
|
229
|
+
*/
|
|
230
|
+
pushCodeBlock(codeBlockId, payload) {
|
|
231
|
+
if (!codeBlockId) return null;
|
|
232
|
+
const step = {
|
|
233
|
+
id: codeBlockId,
|
|
234
|
+
oldContent: payload.oldContent ? cloneDeep(payload.oldContent) : null,
|
|
235
|
+
newContent: payload.newContent ? cloneDeep(payload.newContent) : null,
|
|
236
|
+
changeRecords: payload.changeRecords?.length ? cloneDeep(payload.changeRecords) : void 0,
|
|
237
|
+
historyDescription: payload.historyDescription
|
|
238
|
+
};
|
|
239
|
+
this.getCodeBlockUndoRedo(codeBlockId).pushElement(step);
|
|
240
|
+
this.emit("code-block-history-change", codeBlockId, step);
|
|
241
|
+
return step;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 推入一条数据源变更记录(与页面/节点完全无关),按 `dataSourceId` 维度独立一份 UndoRedo 栈。
|
|
245
|
+
* 行为同 pushCodeBlock(新增 oldSchema=null;删除 newSchema=null)。
|
|
246
|
+
*/
|
|
247
|
+
pushDataSource(dataSourceId, payload) {
|
|
248
|
+
if (!dataSourceId) return null;
|
|
249
|
+
const step = {
|
|
250
|
+
id: dataSourceId,
|
|
251
|
+
oldSchema: payload.oldSchema ? cloneDeep(payload.oldSchema) : null,
|
|
252
|
+
newSchema: payload.newSchema ? cloneDeep(payload.newSchema) : null,
|
|
253
|
+
changeRecords: payload.changeRecords?.length ? cloneDeep(payload.changeRecords) : void 0,
|
|
254
|
+
historyDescription: payload.historyDescription
|
|
255
|
+
};
|
|
256
|
+
this.getDataSourceUndoRedo(dataSourceId).pushElement(step);
|
|
257
|
+
this.emit("data-source-history-change", dataSourceId, step);
|
|
258
|
+
return step;
|
|
259
|
+
}
|
|
260
|
+
/** 撤销指定代码块的最近一次变更。 */
|
|
261
|
+
undoCodeBlock(codeBlockId) {
|
|
262
|
+
const undoRedo = this.state.codeBlockState[codeBlockId];
|
|
263
|
+
if (!undoRedo) return null;
|
|
264
|
+
const step = undoRedo.undo();
|
|
265
|
+
if (step) this.emit("code-block-history-change", codeBlockId, step);
|
|
266
|
+
return step;
|
|
267
|
+
}
|
|
268
|
+
/** 重做指定代码块的下一次变更。 */
|
|
269
|
+
redoCodeBlock(codeBlockId) {
|
|
270
|
+
const undoRedo = this.state.codeBlockState[codeBlockId];
|
|
271
|
+
if (!undoRedo) return null;
|
|
272
|
+
const step = undoRedo.redo();
|
|
273
|
+
if (step) this.emit("code-block-history-change", codeBlockId, step);
|
|
274
|
+
return step;
|
|
275
|
+
}
|
|
276
|
+
/** 是否可对指定代码块撤销。 */
|
|
277
|
+
canUndoCodeBlock(codeBlockId) {
|
|
278
|
+
return this.state.codeBlockState[codeBlockId]?.canUndo() ?? false;
|
|
279
|
+
}
|
|
280
|
+
/** 是否可对指定代码块重做。 */
|
|
281
|
+
canRedoCodeBlock(codeBlockId) {
|
|
282
|
+
return this.state.codeBlockState[codeBlockId]?.canRedo() ?? false;
|
|
283
|
+
}
|
|
284
|
+
/** 撤销指定数据源的最近一次变更。 */
|
|
285
|
+
undoDataSource(dataSourceId) {
|
|
286
|
+
const undoRedo = this.state.dataSourceState[dataSourceId];
|
|
287
|
+
if (!undoRedo) return null;
|
|
288
|
+
const step = undoRedo.undo();
|
|
289
|
+
if (step) this.emit("data-source-history-change", dataSourceId, step);
|
|
290
|
+
return step;
|
|
291
|
+
}
|
|
292
|
+
/** 重做指定数据源的下一次变更。 */
|
|
293
|
+
redoDataSource(dataSourceId) {
|
|
294
|
+
const undoRedo = this.state.dataSourceState[dataSourceId];
|
|
295
|
+
if (!undoRedo) return null;
|
|
296
|
+
const step = undoRedo.redo();
|
|
297
|
+
if (step) this.emit("data-source-history-change", dataSourceId, step);
|
|
298
|
+
return step;
|
|
299
|
+
}
|
|
300
|
+
/** 是否可对指定数据源撤销。 */
|
|
301
|
+
canUndoDataSource(dataSourceId) {
|
|
302
|
+
return this.state.dataSourceState[dataSourceId]?.canUndo() ?? false;
|
|
303
|
+
}
|
|
304
|
+
/** 是否可对指定数据源重做。 */
|
|
305
|
+
canRedoDataSource(dataSourceId) {
|
|
306
|
+
return this.state.dataSourceState[dataSourceId]?.canRedo() ?? false;
|
|
307
|
+
}
|
|
45
308
|
undo() {
|
|
46
309
|
const undoRedo = this.getUndoRedo();
|
|
47
310
|
if (!undoRedo) return null;
|
|
@@ -61,16 +324,148 @@ var History = class extends BaseService_default {
|
|
|
61
324
|
this.removeAllListeners();
|
|
62
325
|
this.removeAllPlugins();
|
|
63
326
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
327
|
+
/**
|
|
328
|
+
* 取出当前活动页的历史步骤平铺列表(包含已应用 + 已撤销)。
|
|
329
|
+
* 列表按时间正序,最早一步在最前面。
|
|
330
|
+
* 通常 UI 应使用 `getPageHistoryGroups` 取已合并分组的版本;本方法仅为兼容/调试保留。
|
|
331
|
+
*/
|
|
332
|
+
getPageStepList(pageId) {
|
|
333
|
+
const targetPageId = pageId ?? this.state.pageId;
|
|
334
|
+
if (!targetPageId) return [];
|
|
335
|
+
const undoRedo = this.state.pageSteps[targetPageId];
|
|
336
|
+
if (!undoRedo) return [];
|
|
337
|
+
const list = undoRedo.getElementList();
|
|
338
|
+
const cursor = undoRedo.getCursor();
|
|
339
|
+
return list.map((step, index) => ({
|
|
340
|
+
step,
|
|
341
|
+
index,
|
|
342
|
+
applied: index < cursor
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* 取出当前活动页的历史栈,按"目标节点"做相邻合并:
|
|
347
|
+
* - 连续修改同一节点(单节点 update)的多步合并为一个 group,组内可展开查看每步;
|
|
348
|
+
* - add / remove / 多节点 update 始终独立成组。
|
|
349
|
+
* 用于历史面板的"页面"tab 展示。
|
|
350
|
+
*/
|
|
351
|
+
getPageHistoryGroups(pageId) {
|
|
352
|
+
const targetPageId = pageId ?? this.state.pageId;
|
|
353
|
+
if (!targetPageId) return [];
|
|
354
|
+
const undoRedo = this.state.pageSteps[targetPageId];
|
|
355
|
+
if (!undoRedo) return [];
|
|
356
|
+
const list = undoRedo.getElementList();
|
|
357
|
+
if (!list.length) return [];
|
|
358
|
+
const cursor = undoRedo.getCursor();
|
|
359
|
+
return History.mergePageSteps(targetPageId, list, cursor);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* 取出全部代码块的历史栈,按 codeBlockId 分组。
|
|
363
|
+
* 同一栈内相邻、同 opType 且作用于同一 id 的多步会被合并为一个 group:
|
|
364
|
+
* - 这正是"代码块/数据源各自按 id 分栈"的天然表现,再叠加"连续修改同目标的相邻步骤合并展示"。
|
|
365
|
+
* - 合并后 group 暴露子步骤数组,UI 可展开查看每一步的 changeRecords。
|
|
366
|
+
* - applied 字段:组内最后一步是否处于已应用段。
|
|
367
|
+
*/
|
|
368
|
+
getCodeBlockHistoryGroups() {
|
|
369
|
+
const groups = [];
|
|
370
|
+
Object.entries(this.state.codeBlockState).forEach(([id, undoRedo]) => {
|
|
371
|
+
if (!undoRedo) return;
|
|
372
|
+
const list = undoRedo.getElementList();
|
|
373
|
+
if (!list.length) return;
|
|
374
|
+
const cursor = undoRedo.getCursor();
|
|
375
|
+
groups.push(...History.mergeCodeBlockSteps(id, list, cursor));
|
|
376
|
+
});
|
|
377
|
+
return groups;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* 读取指定页面历史栈的当前游标(已应用步骤数量)。不传则取当前活动页。
|
|
381
|
+
* 没有对应栈时返回 0。
|
|
382
|
+
*/
|
|
383
|
+
getPageCursor(pageId) {
|
|
384
|
+
const targetPageId = pageId ?? this.state.pageId;
|
|
385
|
+
if (!targetPageId) return 0;
|
|
386
|
+
return this.state.pageSteps[targetPageId]?.getCursor() ?? 0;
|
|
387
|
+
}
|
|
388
|
+
/** 读取指定代码块历史栈的当前游标。 */
|
|
389
|
+
getCodeBlockCursor(codeBlockId) {
|
|
390
|
+
return this.state.codeBlockState[codeBlockId]?.getCursor() ?? 0;
|
|
391
|
+
}
|
|
392
|
+
/** 读取指定数据源历史栈的当前游标。 */
|
|
393
|
+
getDataSourceCursor(dataSourceId) {
|
|
394
|
+
return this.state.dataSourceState[dataSourceId]?.getCursor() ?? 0;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* 取出指定代码块历史栈的平铺步骤列表(含 applied 标记)。供 revert 等按 index 索引步骤使用。
|
|
398
|
+
*/
|
|
399
|
+
getCodeBlockStepList(codeBlockId) {
|
|
400
|
+
const undoRedo = this.state.codeBlockState[codeBlockId];
|
|
401
|
+
if (!undoRedo) return [];
|
|
402
|
+
const list = undoRedo.getElementList();
|
|
403
|
+
const cursor = undoRedo.getCursor();
|
|
404
|
+
return list.map((step, index) => ({
|
|
405
|
+
step,
|
|
406
|
+
index,
|
|
407
|
+
applied: index < cursor
|
|
408
|
+
}));
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* 取出指定数据源历史栈的平铺步骤列表(含 applied 标记)。供 revert 等按 index 索引步骤使用。
|
|
412
|
+
*/
|
|
413
|
+
getDataSourceStepList(dataSourceId) {
|
|
414
|
+
const undoRedo = this.state.dataSourceState[dataSourceId];
|
|
415
|
+
if (!undoRedo) return [];
|
|
416
|
+
const list = undoRedo.getElementList();
|
|
417
|
+
const cursor = undoRedo.getCursor();
|
|
418
|
+
return list.map((step, index) => ({
|
|
419
|
+
step,
|
|
420
|
+
index,
|
|
421
|
+
applied: index < cursor
|
|
422
|
+
}));
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* 取出全部数据源的历史栈,按 dataSourceId 分组。同上。
|
|
426
|
+
*/
|
|
427
|
+
getDataSourceHistoryGroups() {
|
|
428
|
+
const groups = [];
|
|
429
|
+
Object.entries(this.state.dataSourceState).forEach(([id, undoRedo]) => {
|
|
430
|
+
if (!undoRedo) return;
|
|
431
|
+
const list = undoRedo.getElementList();
|
|
432
|
+
if (!list.length) return;
|
|
433
|
+
const cursor = undoRedo.getCursor();
|
|
434
|
+
groups.push(...History.mergeDataSourceSteps(id, list, cursor));
|
|
435
|
+
});
|
|
436
|
+
return groups;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* 取出指定页面的栈;不传 pageId 时按当前活动页取。
|
|
440
|
+
*
|
|
441
|
+
* 跨页 push 时如果目标页的栈尚不存在(用户从未进入过该页),会按需创建一条空栈,
|
|
442
|
+
* 这样切到目标页时 Ctrl+Z 也能撤回该步骤。
|
|
443
|
+
*/
|
|
444
|
+
getUndoRedo(pageId) {
|
|
445
|
+
const targetPageId = pageId ?? this.state.pageId;
|
|
446
|
+
if (!targetPageId) return null;
|
|
447
|
+
if (!this.state.pageSteps[targetPageId]) this.state.pageSteps[targetPageId] = new UndoRedo();
|
|
448
|
+
return this.state.pageSteps[targetPageId];
|
|
67
449
|
}
|
|
68
450
|
setCanUndoRedo() {
|
|
69
451
|
const undoRedo = this.getUndoRedo();
|
|
70
452
|
this.state.canRedo = undoRedo?.canRedo() || false;
|
|
71
453
|
this.state.canUndo = undoRedo?.canUndo() || false;
|
|
72
454
|
}
|
|
73
|
-
|
|
74
|
-
|
|
455
|
+
/**
|
|
456
|
+
* 按 id 获取(或创建)指定代码块的 UndoRedo 栈。
|
|
457
|
+
*/
|
|
458
|
+
getCodeBlockUndoRedo(codeBlockId) {
|
|
459
|
+
if (!this.state.codeBlockState[codeBlockId]) this.state.codeBlockState[codeBlockId] = new UndoRedo();
|
|
460
|
+
return this.state.codeBlockState[codeBlockId];
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* 按 id 获取(或创建)指定数据源的 UndoRedo 栈。
|
|
464
|
+
*/
|
|
465
|
+
getDataSourceUndoRedo(dataSourceId) {
|
|
466
|
+
if (!this.state.dataSourceState[dataSourceId]) this.state.dataSourceState[dataSourceId] = new UndoRedo();
|
|
467
|
+
return this.state.dataSourceState[dataSourceId];
|
|
468
|
+
}
|
|
469
|
+
}();
|
|
75
470
|
//#endregion
|
|
76
471
|
export { history_default as default };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { KeyBindingCommand } from "../type.js";
|
|
2
|
-
import
|
|
2
|
+
import BaseService from "./BaseService.js";
|
|
3
3
|
import editor_default from "./editor.js";
|
|
4
4
|
import ui_default from "./ui.js";
|
|
5
5
|
import { isPage, isPageFragment } from "@tmagic/utils";
|
|
6
6
|
import KeyController from "keycon";
|
|
7
7
|
//#region packages/editor/src/services/keybinding.ts
|
|
8
|
-
var Keybinding = class extends
|
|
8
|
+
var Keybinding = class extends BaseService {
|
|
9
9
|
ctrlKey = /mac os x/.test(navigator.userAgent.toLowerCase()) ? "meta" : "ctrl";
|
|
10
10
|
controllers = /* @__PURE__ */ new Map();
|
|
11
11
|
bindingList = [];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseService from "./BaseService.js";
|
|
2
2
|
import { fillConfig } from "../utils/props.js";
|
|
3
3
|
import editor_default from "./editor.js";
|
|
4
4
|
import { getNodePath, getValueByKeyPath, guid, setValueByKeyPath, toLine } from "@tmagic/utils";
|
|
5
5
|
import { Target, Watcher } from "@tmagic/core";
|
|
6
6
|
import { reactive } from "vue";
|
|
7
|
-
import { cloneDeep, mergeWith } from "lodash-es";
|
|
7
|
+
import { cloneDeep as cloneDeep$1, mergeWith } from "lodash-es";
|
|
8
8
|
//#region packages/editor/src/services/props.ts
|
|
9
9
|
var canUsePluginMethods = {
|
|
10
10
|
async: [
|
|
@@ -17,7 +17,7 @@ var canUsePluginMethods = {
|
|
|
17
17
|
],
|
|
18
18
|
sync: ["createId", "setNewItemId"]
|
|
19
19
|
};
|
|
20
|
-
var Props = class extends
|
|
20
|
+
var Props = class extends BaseService {
|
|
21
21
|
state = reactive({
|
|
22
22
|
propsConfigMap: {},
|
|
23
23
|
propsValueMap: {},
|
|
@@ -57,9 +57,9 @@ var Props = class extends BaseService_default {
|
|
|
57
57
|
getPropsConfigs() {
|
|
58
58
|
return this.state.propsConfigMap;
|
|
59
59
|
}
|
|
60
|
-
async fillConfig(config, labelWidth) {
|
|
60
|
+
async fillConfig(config, labelWidth = "80px") {
|
|
61
61
|
return fillConfig(config, {
|
|
62
|
-
labelWidth
|
|
62
|
+
labelWidth,
|
|
63
63
|
disabledDataSource: this.getDisabledDataSource(),
|
|
64
64
|
disabledCodeBlock: this.getDisabledCodeBlock()
|
|
65
65
|
});
|
|
@@ -77,7 +77,7 @@ var Props = class extends BaseService_default {
|
|
|
77
77
|
*/
|
|
78
78
|
async getPropsConfig(type, data) {
|
|
79
79
|
if (type === "area") return await this.getPropsConfig("button", data);
|
|
80
|
-
return cloneDeep(this.state.propsConfigMap[toLine(type)] || await this.fillConfig([]));
|
|
80
|
+
return cloneDeep$1(this.state.propsConfigMap[toLine(type)] || await this.fillConfig([]));
|
|
81
81
|
}
|
|
82
82
|
hasPropsConfig(type) {
|
|
83
83
|
return !!this.state.propsConfigMap[toLine(type)];
|
|
@@ -116,14 +116,14 @@ var Props = class extends BaseService_default {
|
|
|
116
116
|
}
|
|
117
117
|
const id = this.createId(type);
|
|
118
118
|
const defaultPropsValue = this.getDefaultPropsValue(type);
|
|
119
|
-
const data = this.setNewItemId(cloneDeep({
|
|
119
|
+
const data = this.setNewItemId(cloneDeep$1({
|
|
120
120
|
type,
|
|
121
121
|
...defaultValue
|
|
122
122
|
}));
|
|
123
123
|
return {
|
|
124
124
|
id,
|
|
125
125
|
...defaultPropsValue,
|
|
126
|
-
...mergeWith({}, cloneDeep(this.state.propsValueMap[type] || {}), data)
|
|
126
|
+
...mergeWith({}, cloneDeep$1(this.state.propsValueMap[type] || {}), data)
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
hasPropsValue(type) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseService from "./BaseService.js";
|
|
2
2
|
import editor_default from "./editor.js";
|
|
3
3
|
import { useStage } from "../hooks/use-stage.js";
|
|
4
4
|
import { getIdFromEl } from "@tmagic/utils";
|
|
@@ -13,7 +13,7 @@ var canUsePluginMethods = {
|
|
|
13
13
|
"createStage"
|
|
14
14
|
]
|
|
15
15
|
};
|
|
16
|
-
var StageOverlay = class extends
|
|
16
|
+
var StageOverlay = class extends BaseService {
|
|
17
17
|
state = shallowReactive({
|
|
18
18
|
wrapDiv: document.createElement("div"),
|
|
19
19
|
sourceEl: null,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseService from "./BaseService.js";
|
|
2
2
|
import { getEditorConfig } from "../utils/config.js";
|
|
3
3
|
import serialize from "serialize-javascript";
|
|
4
4
|
//#region packages/editor/src/services/storage.ts
|
|
@@ -24,7 +24,7 @@ var canUsePluginMethods = {
|
|
|
24
24
|
/**
|
|
25
25
|
* 数据存储服务
|
|
26
26
|
*/
|
|
27
|
-
var WebStorage = class extends
|
|
27
|
+
var WebStorage = class extends BaseService {
|
|
28
28
|
storage = globalThis.localStorage;
|
|
29
29
|
namespace = "tmagic";
|
|
30
30
|
constructor() {
|
package/dist/es/services/ui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseService from "./BaseService.js";
|
|
2
2
|
import storage_default, { Protocol } from "./storage.js";
|
|
3
3
|
import editor_default from "./editor.js";
|
|
4
4
|
import "../utils/const.js";
|
|
@@ -48,7 +48,7 @@ var canUsePluginMethods = {
|
|
|
48
48
|
async: ["zoom", "calcZoom"],
|
|
49
49
|
sync: []
|
|
50
50
|
};
|
|
51
|
-
var Ui = class extends
|
|
51
|
+
var Ui = class extends BaseService {
|
|
52
52
|
constructor() {
|
|
53
53
|
super(canUsePluginMethods.async.map((methodName) => ({
|
|
54
54
|
name: methodName,
|