sunrize
Version:
Sunrize — A Multi-Platform X3D Editor
206 lines (145 loc) • 4.55 kB
JavaScript
"use strict";
const
util = require ("util"),
_ = require ("../Application/GetText");
module .exports = class UndoManager
{
static shared = new UndoManager (true);
saveNeeded = false;
undoStack = [ ];
undoFunctions = [ ];
deferFunctions = new Map ();
undoList = [ ];
undoIndex = -1;
undoLabel = _("Undo");
redoLabel = _("Redo");
undo ()
{
if (this .undoIndex < 0)
return;
const undoItem = this .undoList [this .undoIndex];
// Call undo functions.
this .beginUndo (undoItem .description);
for (const undoFunction of undoItem .undoFunctions)
undoFunction ();
// Process deferred functions.
for (const deferFunction of this .deferFunctions .values ())
deferFunction ();
// End undo.
this .undoStack .pop ();
// Assign redo functions.
undoItem .redoFunctions = this .undoFunctions;
this .undoFunctions = [ ];
this .deferFunctions = new Map ();
this .undoIndex -= 1;
this .saveNeeded = true;
// Make labels.
if (this .undoIndex < 0)
this .undoLabel = _("Undo");
else
this .undoLabel = util .format (_("Undo %s"), this .undoList [this .undoIndex] .description)
this .redoLabel = util .format (_("Redo %s"), undoItem .description);
// Propagate change.
this .#processInterests ();
}
redo ()
{
if (this .undoIndex + 1 >= this .undoList .length)
return;
this .undoIndex += 1;
const undoItem = this .undoList [this .undoIndex];
// Call redo functions.
this .beginUndo (undoItem .description);
for (const redoFunction of undoItem .redoFunctions)
redoFunction ();
// Process deferred functions.
for (const deferFunction of this .deferFunctions .values ())
deferFunction ();
// End undo.
this .undoStack .pop ();
// Assign undo functions.
undoItem .undoFunctions = this .undoFunctions;
this .undoFunctions = [ ];
this .deferFunctions = new Map ();
this .saveNeeded = true;
// Make labels.
this .undoLabel = util .format (_("Undo %s"), undoItem .description);
if (this .undoIndex + 1 >= this .undoList .length)
this .redoLabel = _("Redo");
else
this .redoLabel = util .format (_("Redo %s"), this .undoList [this .undoIndex + 1] .description);
// Propagate change.
this .#processInterests ();
}
/**
*
* @param {...string} args description
*/
beginUndo (... args)
{
this .undoStack .push (util .format (... args));
}
endUndo ()
{
const description = this .undoStack .pop ();
if (this .undoStack .length)
return;
// Process deferred functions.
this .undoStack .push (description);
for (const deferFunction of this .deferFunctions .values ())
deferFunction ();
this .undoStack .pop ();
// Test if something happened.
if (!this .undoFunctions .length)
return;
// Assign undo functions.
this .undoList .length = this .undoIndex + 1;
this .undoList .push ({
description: description,
undoFunctions: this .undoFunctions,
});
this .undoFunctions = [ ];
this .deferFunctions = new Map ();
this .undoIndex = this .undoList .length - 1;
this .saveNeeded = true;
// Make labels.
this .undoLabel = util .format (_("Undo %s"), description);
this .redoLabel = _("Redo");
// Propagate change.
this .#processInterests ();
}
/**
*
* @param {function} undoFunction
*/
registerUndo (undoFunction)
{
this .undoFunctions .unshift (undoFunction);
}
/**
* If only key is provided, the function return if there is already a defer function registered.
* @param {*} key
* @param {function=} deferFunction
* @returns
*/
defer (key, deferFunction)
{
if (arguments .length == 1)
return this .deferFunctions .has (key);
this .deferFunctions .set (key, deferFunction);
}
#interest = new Map ();
addInterest (key, callback)
{
this .#interest .set (key, callback);
}
removeInterest (key)
{
this .#interest .delete (key);
}
#processInterests ()
{
for (const callback of this .#interest .values ())
callback ();
}
};