1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00
joplin/ReactNativeClient/lib/services/UndoRedoService.ts
2020-06-13 16:20:18 +01:00

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;
}
}