mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-15 09:04:04 +02:00
104 lines
2.2 KiB
TypeScript
104 lines
2.2 KiB
TypeScript
import AsyncActionQueue from '../AsyncActionQueue';
|
|
const EventEmitter = require('events');
|
|
|
|
class UndoQueue {
|
|
|
|
private inner_: any[] = [];
|
|
private size_: number = 20;
|
|
|
|
pop() {
|
|
return this.inner_.pop();
|
|
}
|
|
|
|
push(e: any) {
|
|
this.inner_.push(e);
|
|
while (this.length > this.size_) {
|
|
this.inner_.splice(0,1);
|
|
}
|
|
}
|
|
|
|
get length(): number {
|
|
return this.inner_.length;
|
|
}
|
|
|
|
at(index: number): any {
|
|
return this.inner_[index];
|
|
}
|
|
|
|
}
|
|
|
|
export default class UndoRedoService {
|
|
|
|
private pushAsyncQueue: AsyncActionQueue = new AsyncActionQueue(700);
|
|
private undoStates: UndoQueue = new UndoQueue();
|
|
private redoStates: UndoQueue = new UndoQueue();
|
|
private eventEmitter: any = new EventEmitter();
|
|
private isUndoing: boolean = false;
|
|
|
|
constructor() {
|
|
this.push = this.push.bind(this);
|
|
}
|
|
|
|
on(eventName: string, callback: Function) {
|
|
return this.eventEmitter.on(eventName, callback);
|
|
}
|
|
|
|
off(eventName: string, callback: Function) {
|
|
return this.eventEmitter.removeListener(eventName, callback);
|
|
}
|
|
|
|
push(state: any) {
|
|
this.undoStates.push(state);
|
|
this.redoStates = new UndoQueue();
|
|
this.eventEmitter.emit('stackChange');
|
|
}
|
|
|
|
schedulePush(state: any) {
|
|
this.pushAsyncQueue.push(async () => {
|
|
this.push(state);
|
|
});
|
|
}
|
|
|
|
async undo(redoState: any) {
|
|
if (this.isUndoing) return;
|
|
if (!this.canUndo) throw new Error('Nothing to undo');
|
|
this.isUndoing = true;
|
|
await this.pushAsyncQueue.processAllNow();
|
|
const state = this.undoStates.pop();
|
|
this.redoStates.push(redoState);
|
|
this.eventEmitter.emit('stackChange');
|
|
this.isUndoing = false;
|
|
return state;
|
|
}
|
|
|
|
async redo(undoState: any) {
|
|
if (this.isUndoing) return;
|
|
if (!this.canRedo) throw new Error('Nothing to redo');
|
|
this.isUndoing = true;
|
|
await this.pushAsyncQueue.processAllNow();
|
|
const state = this.redoStates.pop();
|
|
this.undoStates.push(undoState);
|
|
this.eventEmitter.emit('stackChange');
|
|
this.isUndoing = false;
|
|
return state;
|
|
}
|
|
|
|
async reset() {
|
|
this.undoStates = new UndoQueue();
|
|
this.redoStates = new UndoQueue();
|
|
this.isUndoing = false;
|
|
const output = this.pushAsyncQueue.reset();
|
|
this.eventEmitter.emit('stackChange');
|
|
return output;
|
|
}
|
|
|
|
get canUndo(): boolean {
|
|
return !!this.undoStates.length;
|
|
}
|
|
|
|
get canRedo(): boolean {
|
|
return !!this.redoStates.length;
|
|
}
|
|
|
|
}
|