@tmagic/editor 1.8.0-beta.6 → 1.8.0-beta.8
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/components/CompareForm.vue_vue_type_script_setup_true_lang.js +10 -6
- package/dist/es/index.js +6 -4
- package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +38 -26
- package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +5 -1
- package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +163 -310
- package/dist/es/layouts/history-list/composables.js +47 -128
- package/dist/es/layouts/history-list/useHistoryList.js +56 -0
- package/dist/es/layouts/history-list/useHistoryRevert.js +304 -0
- package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/es/services/codeBlock.js +32 -28
- package/dist/es/services/dataSource.js +43 -34
- package/dist/es/services/editor.js +31 -26
- package/dist/es/services/history.js +268 -384
- package/dist/es/style.css +12 -0
- package/dist/es/utils/editor.js +2 -2
- package/dist/es/utils/history.js +35 -47
- package/dist/style.css +12 -0
- package/dist/tmagic-editor.umd.cjs +3808 -3090
- package/package.json +7 -7
- package/src/components/CompareForm.vue +14 -6
- package/src/index.ts +2 -0
- package/src/layouts/NavMenu.vue +2 -2
- package/src/layouts/history-list/GroupRow.vue +10 -0
- package/src/layouts/history-list/HistoryDiffDialog.vue +6 -1
- package/src/layouts/history-list/HistoryListPanel.vue +60 -270
- package/src/layouts/history-list/PageTab.vue +4 -4
- package/src/layouts/history-list/composables.ts +82 -180
- package/src/layouts/history-list/useHistoryList.ts +60 -0
- package/src/layouts/history-list/useHistoryRevert.ts +400 -0
- package/src/layouts/sidebar/Sidebar.vue +2 -2
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +5 -4
- package/src/services/codeBlock.ts +30 -29
- package/src/services/dataSource.ts +37 -37
- package/src/services/editor.ts +32 -29
- package/src/services/history.ts +340 -431
- package/src/theme/history-list-panel.scss +14 -0
- package/src/type.ts +179 -100
- package/src/utils/editor.ts +2 -2
- package/src/utils/history.ts +52 -74
- package/types/index.d.ts +435 -309
|
@@ -20,7 +20,7 @@ import type {
|
|
|
20
20
|
} from '@editor/type';
|
|
21
21
|
import { getFormConfig, getFormValue } from '@editor/utils/data-source';
|
|
22
22
|
import { COPY_DS_STORAGE_KEY } from '@editor/utils/editor';
|
|
23
|
-
import { describeRevertStep, getLastPushedHistoryIds } from '@editor/utils/history';
|
|
23
|
+
import { createStackStep, describeRevertStep, getLastPushedHistoryIds } from '@editor/utils/history';
|
|
24
24
|
|
|
25
25
|
import BaseService from './BaseService';
|
|
26
26
|
|
|
@@ -137,13 +137,13 @@ class DataSource extends BaseService {
|
|
|
137
137
|
this.get('dataSources').push(newConfig);
|
|
138
138
|
|
|
139
139
|
if (!doNotPushHistory) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
140
|
+
const step = createStackStep<DataSourceSchema, DataSourceStepValue>(newConfig.id, {
|
|
141
|
+
oldValue: null,
|
|
142
|
+
newValue: newConfig,
|
|
143
|
+
historyDescription,
|
|
144
|
+
source: historySource,
|
|
145
|
+
});
|
|
146
|
+
this.lastPushedHistoryId = (step ? historyService.push('dataSource', step, newConfig.id) : null)?.uuid ?? null;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
this.emit('add', newConfig);
|
|
@@ -178,14 +178,14 @@ class DataSource extends BaseService {
|
|
|
178
178
|
dataSources[index] = newConfig;
|
|
179
179
|
|
|
180
180
|
if (!doNotPushHistory) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
181
|
+
const step = createStackStep<DataSourceSchema, DataSourceStepValue>(newConfig.id, {
|
|
182
|
+
oldValue: oldConfig ? cloneDeep(oldConfig) : null,
|
|
183
|
+
newValue: newConfig,
|
|
184
|
+
changeRecords,
|
|
185
|
+
historyDescription,
|
|
186
|
+
source: historySource,
|
|
187
|
+
});
|
|
188
|
+
this.lastPushedHistoryId = (step ? historyService.push('dataSource', step, newConfig.id) : null)?.uuid ?? null;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
this.emit('update', newConfig, {
|
|
@@ -210,13 +210,13 @@ class DataSource extends BaseService {
|
|
|
210
210
|
dataSources.splice(index, 1);
|
|
211
211
|
|
|
212
212
|
if (oldConfig && !doNotPushHistory) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
213
|
+
const step = createStackStep<DataSourceSchema, DataSourceStepValue>(id, {
|
|
214
|
+
oldValue: cloneDeep(oldConfig),
|
|
215
|
+
newValue: null,
|
|
216
|
+
historyDescription,
|
|
217
|
+
source: historySource,
|
|
218
|
+
});
|
|
219
|
+
this.lastPushedHistoryId = (step ? historyService.push('dataSource', step, id) : null)?.uuid ?? null;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
this.emit('remove', id);
|
|
@@ -270,7 +270,7 @@ class DataSource extends BaseService {
|
|
|
270
270
|
* @returns 撤销的 step;栈不存在或已无可撤销时返回 null
|
|
271
271
|
*/
|
|
272
272
|
public undo(id: Id) {
|
|
273
|
-
const step = historyService.
|
|
273
|
+
const step = historyService.undo('dataSource', id);
|
|
274
274
|
if (!step) return null;
|
|
275
275
|
this.applyHistoryStep(step, true);
|
|
276
276
|
return step;
|
|
@@ -282,7 +282,7 @@ class DataSource extends BaseService {
|
|
|
282
282
|
* @returns 重做的 step;栈不存在或已无可重做时返回 null
|
|
283
283
|
*/
|
|
284
284
|
public redo(id: Id) {
|
|
285
|
-
const step = historyService.
|
|
285
|
+
const step = historyService.redo('dataSource', id);
|
|
286
286
|
if (!step) return null;
|
|
287
287
|
this.applyHistoryStep(step, false);
|
|
288
288
|
return step;
|
|
@@ -290,12 +290,12 @@ class DataSource extends BaseService {
|
|
|
290
290
|
|
|
291
291
|
/** 是否可对指定数据源撤销。 */
|
|
292
292
|
public canUndo(id: Id): boolean {
|
|
293
|
-
return historyService.
|
|
293
|
+
return historyService.canUndo('dataSource', id);
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
/** 是否可对指定数据源重做。 */
|
|
297
297
|
public canRedo(id: Id): boolean {
|
|
298
|
-
return historyService.
|
|
298
|
+
return historyService.canRedo('dataSource', id);
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
/**
|
|
@@ -306,7 +306,7 @@ class DataSource extends BaseService {
|
|
|
306
306
|
* @returns 实际移动到的最终游标位置
|
|
307
307
|
*/
|
|
308
308
|
public goto(id: Id, targetCursor: number): number {
|
|
309
|
-
let cursor = historyService.
|
|
309
|
+
let cursor = historyService.getCursor('dataSource', id);
|
|
310
310
|
const target = Math.max(0, targetCursor);
|
|
311
311
|
while (cursor > target) {
|
|
312
312
|
if (!this.undo(id)) break;
|
|
@@ -330,13 +330,13 @@ class DataSource extends BaseService {
|
|
|
330
330
|
* @returns 反向后产生的新 step;目标不存在 / 未应用时返回 null
|
|
331
331
|
*/
|
|
332
332
|
public revert(id: Id, index: number): DataSourceStepValue | null {
|
|
333
|
-
const list = historyService.
|
|
333
|
+
const list = historyService.getStepList('dataSource', id);
|
|
334
334
|
const entry = list[index];
|
|
335
335
|
if (!entry?.applied) return null;
|
|
336
336
|
// 更新类步骤(前后 schema 都存在)必须带 changeRecords 才支持回滚,否则只能整 schema 替换,会冲掉后续无关变更。
|
|
337
337
|
const { oldSchema, newSchema, changeRecords } = entry.step.diff?.[0] ?? {};
|
|
338
338
|
if (oldSchema && newSchema && !changeRecords?.length) return null;
|
|
339
|
-
const description = `回滚 #${index + 1}: ${describeRevertStep<DataSourceSchema>(entry.step.id, entry.step.diff?.[0], (s) => s.title)}`;
|
|
339
|
+
const description = `回滚 #${index + 1}: ${describeRevertStep<DataSourceSchema>(entry.step.data.id, entry.step.diff?.[0], (s) => s.title)}`;
|
|
340
340
|
return this.applyRevertStep(entry.step, description);
|
|
341
341
|
}
|
|
342
342
|
|
|
@@ -349,7 +349,7 @@ class DataSource extends BaseService {
|
|
|
349
349
|
*/
|
|
350
350
|
public revertById(uuids: string[]): (DataSourceStepValue | null)[] {
|
|
351
351
|
return uuids.map((uuid) => {
|
|
352
|
-
const location = historyService.
|
|
352
|
+
const location = historyService.findStepLocationByUuid('dataSource', uuid);
|
|
353
353
|
if (!location) return null;
|
|
354
354
|
return this.revert(location.id, location.index);
|
|
355
355
|
});
|
|
@@ -435,19 +435,19 @@ class DataSource extends BaseService {
|
|
|
435
435
|
* 同构,差异仅在于走对应的公共 add / update / remove 而不是带 doNotPushHistory 的版本。
|
|
436
436
|
*/
|
|
437
437
|
private applyRevertStep(step: DataSourceStepValue, historyDescription: string): DataSourceStepValue | null {
|
|
438
|
-
const { id } = step;
|
|
438
|
+
const { id } = step.data;
|
|
439
439
|
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
440
440
|
|
|
441
441
|
// 原本是新增 → revert 即删除
|
|
442
442
|
if (!oldSchema && newSchema) {
|
|
443
443
|
this.remove(`${id}`, { historyDescription, historySource: 'rollback' });
|
|
444
|
-
return historyService.
|
|
444
|
+
return historyService.getStepList('dataSource', id).slice(-1)[0]?.step ?? null;
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
// 原本是删除 → revert 即重新加回
|
|
448
448
|
if (oldSchema && !newSchema) {
|
|
449
449
|
this.add(cloneDeep(oldSchema), { historyDescription, historySource: 'rollback' });
|
|
450
|
-
return historyService.
|
|
450
|
+
return historyService.getStepList('dataSource', id).slice(-1)[0]?.step ?? null;
|
|
451
451
|
}
|
|
452
452
|
|
|
453
453
|
if (!oldSchema || !newSchema) return null;
|
|
@@ -471,11 +471,11 @@ class DataSource extends BaseService {
|
|
|
471
471
|
historyDescription,
|
|
472
472
|
historySource: 'rollback',
|
|
473
473
|
});
|
|
474
|
-
return historyService.
|
|
474
|
+
return historyService.getStepList('dataSource', id).slice(-1)[0]?.step ?? null;
|
|
475
475
|
}
|
|
476
476
|
|
|
477
477
|
this.update(cloneDeep(oldSchema), { historyDescription, historySource: 'rollback' });
|
|
478
|
-
return historyService.
|
|
478
|
+
return historyService.getStepList('dataSource', id).slice(-1)[0]?.step ?? null;
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
/**
|
|
@@ -493,7 +493,7 @@ class DataSource extends BaseService {
|
|
|
493
493
|
* @param reverse true=撤销,false=重做
|
|
494
494
|
*/
|
|
495
495
|
private applyHistoryStep(step: DataSourceStepValue, reverse: boolean): void {
|
|
496
|
-
const { id } = step;
|
|
496
|
+
const { id } = step.data;
|
|
497
497
|
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
498
498
|
|
|
499
499
|
// 新增 / 删除:直接 add 或 remove,不走 patch 逻辑
|
package/src/services/editor.ts
CHANGED
|
@@ -165,8 +165,8 @@ class Editor extends BaseService {
|
|
|
165
165
|
// 重复创建,set root 不额外产生记录,由恢复出的历史栈作为当前状态来源。
|
|
166
166
|
// 标记不进入撤销/重做栈,仅作为该页历史列表底部的初始基线展示。
|
|
167
167
|
app.items?.forEach((pageNode) => {
|
|
168
|
-
if (pageNode?.id !== undefined && !historyService.
|
|
169
|
-
historyService.
|
|
168
|
+
if (pageNode?.id !== undefined && !historyService.getMarker('page', pageNode.id)) {
|
|
169
|
+
historyService.setMarker('page', pageNode.id, {
|
|
170
170
|
name: pageNode.name,
|
|
171
171
|
source: options.historySource,
|
|
172
172
|
});
|
|
@@ -297,12 +297,6 @@ class Editor extends BaseService {
|
|
|
297
297
|
this.set('page', page);
|
|
298
298
|
this.set('parent', parent);
|
|
299
299
|
|
|
300
|
-
if (page) {
|
|
301
|
-
historyService.changePage(toRaw(page));
|
|
302
|
-
} else {
|
|
303
|
-
historyService.resetState();
|
|
304
|
-
}
|
|
305
|
-
|
|
306
300
|
if (node?.id) {
|
|
307
301
|
this.get('stage')
|
|
308
302
|
?.renderer?.runtime?.getApp?.()
|
|
@@ -586,8 +580,6 @@ class Editor extends BaseService {
|
|
|
586
580
|
stage?.select(pages[0].id);
|
|
587
581
|
} else {
|
|
588
582
|
this.selectRoot();
|
|
589
|
-
|
|
590
|
-
historyService.resetPage();
|
|
591
583
|
}
|
|
592
584
|
};
|
|
593
585
|
|
|
@@ -1320,7 +1312,9 @@ class Editor extends BaseService {
|
|
|
1320
1312
|
* @returns 被撤销的操作
|
|
1321
1313
|
*/
|
|
1322
1314
|
public async undo(): Promise<StepValue | null> {
|
|
1323
|
-
const
|
|
1315
|
+
const pageId = this.get('page')?.id;
|
|
1316
|
+
if (pageId === undefined) return null;
|
|
1317
|
+
const value = historyService.undo('page', pageId);
|
|
1324
1318
|
if (value) {
|
|
1325
1319
|
await this.applyHistoryOp(value, true);
|
|
1326
1320
|
}
|
|
@@ -1332,7 +1326,9 @@ class Editor extends BaseService {
|
|
|
1332
1326
|
* @returns 被恢复的操作
|
|
1333
1327
|
*/
|
|
1334
1328
|
public async redo(): Promise<StepValue | null> {
|
|
1335
|
-
const
|
|
1329
|
+
const pageId = this.get('page')?.id;
|
|
1330
|
+
if (pageId === undefined) return null;
|
|
1331
|
+
const value = historyService.redo('page', pageId);
|
|
1336
1332
|
if (value) {
|
|
1337
1333
|
await this.applyHistoryOp(value, false);
|
|
1338
1334
|
}
|
|
@@ -1356,7 +1352,7 @@ class Editor extends BaseService {
|
|
|
1356
1352
|
* @returns 反向后产生的新 step;目标不存在 / 未应用 / 反向失败时返回 null
|
|
1357
1353
|
*/
|
|
1358
1354
|
public async revertPageStep(index: number): Promise<StepValue | null> {
|
|
1359
|
-
const list = historyService.
|
|
1355
|
+
const list = historyService.getStepList('page', this.get('page')?.id);
|
|
1360
1356
|
const entry = list[index];
|
|
1361
1357
|
if (!entry?.applied) return null;
|
|
1362
1358
|
|
|
@@ -1374,7 +1370,8 @@ class Editor extends BaseService {
|
|
|
1374
1370
|
|
|
1375
1371
|
// 反向应用产生的新 step 由内部 pushOpHistory 触发 history `change` 事件,监听一次以拿到引用。
|
|
1376
1372
|
let revertedStep: StepValue | null = null;
|
|
1377
|
-
|
|
1373
|
+
// page 的 `change` 事件回调签名为 `(pageId, step)`,这里只关心被回滚产生的新 step。
|
|
1374
|
+
const captureRevert = (_pageId: Id, s: StepValue) => {
|
|
1378
1375
|
revertedStep = s;
|
|
1379
1376
|
};
|
|
1380
1377
|
historyService.once('change', captureRevert);
|
|
@@ -1461,9 +1458,10 @@ class Editor extends BaseService {
|
|
|
1461
1458
|
*/
|
|
1462
1459
|
public async revertPageStepById(uuids: string[]): Promise<(StepValue | null)[]> {
|
|
1463
1460
|
const results: (StepValue | null)[] = [];
|
|
1461
|
+
const pageId = this.get('page')?.id;
|
|
1464
1462
|
for (const uuid of uuids) {
|
|
1465
|
-
const
|
|
1466
|
-
results.push(
|
|
1463
|
+
const location = historyService.findStepLocationByUuid('page', uuid, pageId);
|
|
1464
|
+
results.push(!location ? null : await this.revertPageStep(location.index));
|
|
1467
1465
|
}
|
|
1468
1466
|
return results;
|
|
1469
1467
|
}
|
|
@@ -1478,8 +1476,9 @@ class Editor extends BaseService {
|
|
|
1478
1476
|
* @returns 实际移动到的最终游标位置
|
|
1479
1477
|
*/
|
|
1480
1478
|
public async gotoPageStep(targetCursor: number): Promise<number> {
|
|
1481
|
-
|
|
1482
|
-
|
|
1479
|
+
const pageId = this.get('page')?.id;
|
|
1480
|
+
let cursor = historyService.getCursor('page', pageId);
|
|
1481
|
+
const { length } = historyService.getStepList('page', pageId);
|
|
1483
1482
|
const target = Math.max(0, Math.min(targetCursor, length));
|
|
1484
1483
|
while (cursor > target) {
|
|
1485
1484
|
const step = await this.undo();
|
|
@@ -1628,9 +1627,11 @@ class Editor extends BaseService {
|
|
|
1628
1627
|
uuid: guid(),
|
|
1629
1628
|
data: { name: page.name || '', id: page.id },
|
|
1630
1629
|
opType,
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1630
|
+
extra: {
|
|
1631
|
+
selectedBefore: [],
|
|
1632
|
+
selectedAfter: [],
|
|
1633
|
+
modifiedNodeIds: new Map(),
|
|
1634
|
+
},
|
|
1634
1635
|
diff: [diffItem],
|
|
1635
1636
|
rootStep: true,
|
|
1636
1637
|
};
|
|
@@ -1638,9 +1639,9 @@ class Editor extends BaseService {
|
|
|
1638
1639
|
|
|
1639
1640
|
const top = historyService.getCurrentPageStep(page.id);
|
|
1640
1641
|
if (top?.rootStep && top.source === source) {
|
|
1641
|
-
historyService.
|
|
1642
|
+
historyService.replaceCurrentStep('page', step, page.id);
|
|
1642
1643
|
} else {
|
|
1643
|
-
historyService.push(step, page.id);
|
|
1644
|
+
historyService.push('page', step, page.id);
|
|
1644
1645
|
}
|
|
1645
1646
|
}
|
|
1646
1647
|
|
|
@@ -1662,16 +1663,18 @@ class Editor extends BaseService {
|
|
|
1662
1663
|
uuid: guid(),
|
|
1663
1664
|
data: pageData,
|
|
1664
1665
|
opType,
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1666
|
+
extra: {
|
|
1667
|
+
selectedBefore: this.selectionBeforeOp ?? [],
|
|
1668
|
+
selectedAfter: this.get('nodes').map((n) => n.id),
|
|
1669
|
+
modifiedNodeIds: new Map(this.get('modifiedNodeIds')),
|
|
1670
|
+
},
|
|
1668
1671
|
diff,
|
|
1669
1672
|
};
|
|
1670
1673
|
if (historyDescription) step.historyDescription = historyDescription;
|
|
1671
1674
|
if (source) step.source = source;
|
|
1672
1675
|
// 显式按 step.data.id 入栈:跨页操作(如 moveToContainer 从源页搬到目标页)
|
|
1673
1676
|
// 必须落到正确的页面栈,否则会把记录错误地推到当前活动页 / 操作发起页。
|
|
1674
|
-
const pushed = historyService.push(step, pageData.id);
|
|
1677
|
+
const pushed = historyService.push('page', step, pageData.id);
|
|
1675
1678
|
// push 返回 null 表示当前没有可写入的页面栈(未真正入栈),此时不应返回 uuid。
|
|
1676
1679
|
const historyId = pushed ? step.uuid : null;
|
|
1677
1680
|
this.lastPushedHistoryId = historyId;
|
|
@@ -1799,11 +1802,11 @@ class Editor extends BaseService {
|
|
|
1799
1802
|
}
|
|
1800
1803
|
}
|
|
1801
1804
|
|
|
1802
|
-
this.set('modifiedNodeIds', step.modifiedNodeIds);
|
|
1805
|
+
this.set('modifiedNodeIds', step.extra?.modifiedNodeIds ?? new Map());
|
|
1803
1806
|
|
|
1804
1807
|
const page = toRaw(this.get('page'));
|
|
1805
1808
|
if (page) {
|
|
1806
|
-
const selectIds = reverse ? step.selectedBefore : step.selectedAfter;
|
|
1809
|
+
const selectIds = (reverse ? step.extra?.selectedBefore : step.extra?.selectedAfter) ?? [];
|
|
1807
1810
|
setTimeout(() => {
|
|
1808
1811
|
if (!selectIds.length) return;
|
|
1809
1812
|
|