94 lines
2.5 KiB
TypeScript
94 lines
2.5 KiB
TypeScript
export type HistoryHandler = {
|
|
undo: (action: HistoryAction) => void;
|
|
redo: (action: HistoryAction) => void;
|
|
}
|
|
|
|
interface HistoryEvent
|
|
{
|
|
source: string;
|
|
event: string;
|
|
actions: HistoryAction[];
|
|
}
|
|
interface HistoryAction
|
|
{
|
|
element: any;
|
|
from?: any;
|
|
to?: any;
|
|
}
|
|
|
|
export class History
|
|
{
|
|
private handlers: Record<string, { handlers: Record<string, HistoryHandler>, any?: (action: HistoryAction) => void }>;
|
|
private history: HistoryEvent[];
|
|
private position: number;
|
|
|
|
constructor()
|
|
{
|
|
this.handlers = {};
|
|
this.history = [];
|
|
this.position = -1;
|
|
}
|
|
get last()
|
|
{
|
|
return this.history.length > 0 && this.position > -1 ? this.history[this.position] : undefined;
|
|
}
|
|
get undoable()
|
|
{
|
|
return this.history && this.position !== -1;
|
|
}
|
|
get redoable()
|
|
{
|
|
return this.history && this.position < this.history.length - 1;
|
|
}
|
|
undo()
|
|
{
|
|
const last = this.last;
|
|
if(!last)
|
|
return;
|
|
|
|
last.actions.forEach(e => {
|
|
this.handlers[last.source] && this.handlers[last.source].handlers[last.event]?.undo(e)
|
|
this.handlers[last.source] && this.handlers[last.source].any && this.handlers[last.source].any!(e);
|
|
});
|
|
|
|
this.position--;
|
|
}
|
|
redo()
|
|
{
|
|
if(!this.history || this.history.length - 1 <= this.position)
|
|
return;
|
|
|
|
this.position++;
|
|
|
|
const last = this.last;
|
|
if(!last)
|
|
{
|
|
this.position--;
|
|
return;
|
|
}
|
|
|
|
last.actions.forEach(e => {
|
|
this.handlers[last.source] && this.handlers[last.source].handlers[last.event]?.redo(e)
|
|
this.handlers[last.source] && this.handlers[last.source].any && this.handlers[last.source].any!(e);
|
|
});
|
|
}
|
|
add(source: string, event: string, actions: HistoryAction[], apply: boolean = false)
|
|
{
|
|
this.position++;
|
|
this.history.splice(this.position, history.length - this.position, { source, event, actions });
|
|
|
|
if(apply)
|
|
actions.forEach(e => {
|
|
this.handlers[source] && this.handlers[source].handlers[event]?.redo(e);
|
|
this.handlers[source] && this.handlers[source].any && this.handlers[source].any(e);
|
|
});
|
|
}
|
|
register(source: string, handlers: Record<string, HistoryHandler>, any?: (action: HistoryAction) => void)
|
|
{
|
|
this.handlers[source] = { handlers, any };
|
|
}
|
|
unregister(source: string)
|
|
{
|
|
delete this.handlers[source];
|
|
}
|
|
} |