From 708707653608e65ee95e2d69c75f0d86b8474c6d Mon Sep 17 00:00:00 2001 From: Zhilin Liu Date: Tue, 16 Jan 2024 22:29:07 +0800 Subject: [PATCH] feat: history for MapStore (#78) --- src/Kernel/HistoryManager.ts | 11 ++++++- src/Kernel/Store/MapStore.ts | 32 +++++++++++++++---- src/Kernel/index.ts | 4 +-- src/UserInterface/Present/Present.vue | 8 +++-- .../ToolBar/components/Home/UndoRedo.vue | 9 ++++-- 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/Kernel/HistoryManager.ts b/src/Kernel/HistoryManager.ts index 68a75d7..2f02da1 100644 --- a/src/Kernel/HistoryManager.ts +++ b/src/Kernel/HistoryManager.ts @@ -19,6 +19,7 @@ export class HistoryManager { private _undoStack: Array = [] private _redoStack: Array = [] + private _timerId?: NodeJS.Timeout private _merging = false private _currentStep: Step = [] @@ -34,6 +35,14 @@ export class HistoryManager { return this._redoStack.length > 0 } + clear() { + clearTimeout(this._timerId) + this._merging = false + this._currentStep = [] + this._undoStack = [] + this._redoStack = [] + } + exec(command: Command) { if (this._redoStack.length > 0) { this._redoStack = [] @@ -42,7 +51,7 @@ export class HistoryManager { if (!this._merging) { this._merging = true this._currentStep.push(command) - setTimeout(() => { + this._timerId = setTimeout(() => { this._undoStack.push(this._currentStep) this.events.update.emit('exec') this._merging = false diff --git a/src/Kernel/Store/MapStore.ts b/src/Kernel/Store/MapStore.ts index cd01a03..9e94c73 100644 --- a/src/Kernel/Store/MapStore.ts +++ b/src/Kernel/Store/MapStore.ts @@ -1,6 +1,8 @@ import { EventManager } from '@Kernel/EventManager' import type { FullType, OriginMap, StoreType } from './_Store' import { isStoreType } from './_Store' +import { Command } from '@Kernel/HistoryManager' +import { history } from '@Kernel/index' export class MapStore { private _store: { [key: string]: FullType } = Object.create(null) @@ -9,24 +11,42 @@ export class MapStore { update: new EventManager<{ key: string; from: FullType; to: FullType }>(), } - get(key: string): FullType { - return this._store[key] - } - - set(key: string, value: FullType) { + private _set(key: string, value: FullType) { const from = this._store[key] const to = value this._store[key] = value this.events.update.emit({ key, from, to }) } - delete(key: string) { + private _delete(key: string) { const from = this._store[key] const to = undefined delete this._store[key] this.events.update.emit({ key, from, to }) } + get(key: string): FullType { + return this._store[key] + } + + set(key: string, value: FullType) { + const oldValue = this.get(key) + const command = new Command( + () => this._set(key, value), + () => this._set(key, oldValue) + ) + history.exec(command) + } + + delete(key: string) { + const oldValue = this.get(key) + const command = new Command( + () => this._delete(key), + () => this._set(key, oldValue) + ) + history.exec(command) + } + toPlain(): OriginMap { const result = Object.create(null) for (const [key, value] of Object.entries(this._store)) { diff --git a/src/Kernel/index.ts b/src/Kernel/index.ts index 77d5dff..cba3eb4 100644 --- a/src/Kernel/index.ts +++ b/src/Kernel/index.ts @@ -18,14 +18,14 @@ interface RichTextStateChange { export type SlideMode = 'edit' | 'start' | 'current' +export const history = new HistoryManager() + export const slideManager = new SlideManager([ new Slide([new TextBoxBlock(330, 120, TEXT_BOX_DEFAULT_WIDTH, TEXT_BOX_DEFAULT_HEIGHT, 'center')]), ]) export const richTextObserver = new EventManager() -export const history = new HistoryManager() - export const selectionManager = new SelectionManager() export const slideShowMode = new EventManager() diff --git a/src/UserInterface/Present/Present.vue b/src/UserInterface/Present/Present.vue index 979b7a7..b3701d3 100644 --- a/src/UserInterface/Present/Present.vue +++ b/src/UserInterface/Present/Present.vue @@ -4,8 +4,8 @@ import SlideList from '../SlideList/SlideList.vue' import SlideContainer from '../Slide/SlideContainer.vue' import StatusBar from '../StatusBar/StatusBar.vue' import Show from '../Show/Show.vue' -import { type SlideMode, slideShowMode } from '@Kernel/index' -import { ref } from 'vue' +import { type SlideMode, slideShowMode, history } from '@Kernel/index' +import { ref, onMounted } from 'vue' const currentMode = ref('edit') slideShowMode.on(async (mode) => { @@ -21,6 +21,10 @@ document.addEventListener('fullscreenchange', () => { currentMode.value = 'edit' } }) + +onMounted(() => { + history.clear() +})