Install Oops.js via npm
masterTo use Oops.js in your project, install the package using npm and then import the Oops class.
npm install @heyputer/oops.jsimport Oops from '@heyputer/oops.js';repository·master·Indexed 20 days ago
https://github.com/heyputer/oops.jsAn advanced undo/redo manager for JavaScript applications that implements the Command Pattern. It provides robust history management for complex tools, featuring transactions for atomic operations, command merging, state serialization (export/import), and CompositeCommand for grouping sub-commands. It includes configurable options for stack size, snapshot intervals, and compression thresholds.
To use Oops.js in your project, install the package using npm and then import the Oops class.
npm install @heyputer/oops.jsimport Oops from '@heyputer/oops.js';You can include Oops.js directly in your HTML file using a script tag. This makes the Oops class available globally in your JavaScript environment.
<script src="https://cdn.jsdelivr.net/npm/@heyputer/oops.js@latest/dist/oops.min.js"></script>Transactions allow you to group multiple commands so they are treated as a single atomic unit in the undo/redo history.
beginTransaction() to start a group.execute() for each command you want in the group. These commands are held in a temporary buffer.commitTransaction() to finalize the group. If the transaction contains multiple commands, they are wrapped in a CompositeCommand and added to the undo stack as one entry.abortTransaction() if you want to cancel the group. This undoes all commands executed since beginTransaction() in reverse order.undoRedoManager.beginTransaction();
try {
undoRedoManager.execute(command1);
undoRedoManager.execute(command2);
undoRedoManager.commitTransaction();
} catch (e) {
undoRedoManager.abortTransaction();
}Create an instance of Oops to manage undo/redo history, transactions, and command execution. You can pass an options object to configure the behavior of the history management.
Configuration Options:
maxStackSize (Number): Maximum number of commands in the undo stack. Defaults to Infinity.snapshotInterval (Number): How often to create a state snapshot (based on undo stack size). Defaults to 10.compressThreshold (Number): The undo stack size at which history compression is triggered. Defaults to 100.mergeWindow (Number): Time window in milliseconds for merging consecutive commands. Defaults to 1000.const Oops = require('oops.js');
const undoRedoManager = new Oops({
maxStackSize: 50,
snapshotInterval: 5,
compressThreshold: 20,
mergeWindow: 2000
});To use Oops.js, you define commands as classes with execute() and undo() methods. You then pass instances of these commands to the undoManager.execute() method.
// Create an instance of Oops
const undoManager = new Oops();
// Define a simple command
class AddNumberCommand {
constructor(number) {
this.number = number;
this.previousTotal = 0;
}
execute() {
this.previousTotal = total;
total += this.number;
}
undo() {
total = this.previousTotal;
}
}
// Use the undo manager
let total = 0;
undoManager.execute(new AddNumberCommand(5));
console.log(total); // Output: 5
undoManager.execute(new AddNumberCommand(3));
console.log(total); // Output: 8
undoManager.undo();
console.log(total); // Output: 5
undoManager.redo();
console.log(total); // Output: 8Use these boolean properties to enable or disable UI elements (like undo/redo buttons) based on the current state of the history.
if (undoManager.canUndo) {
undoButton.disabled = false;
} else {
undoButton.disabled = true;
}A CompositeCommand allows you to treat a collection of multiple commands as a single command. When the composite command is undone, all sub-commands are undone in reverse order.
const composite = new CompositeCommand([cmd1, cmd2, cmd3]);
undoManager.execute(composite);The execute method runs a command and adds it to the undo stack.
undoManager.execute(command, options);Group multiple commands into a single atomic operation using transaction methods. This ensures that a group of commands is treated as one unit in the undo/redo history.
undoManager.beginTransaction();
// ... execute multiple commands ...
undoManager.commitTransaction();
// Or to cancel:
undoManager.abortTransaction();Persist the undo/redo history by exporting the state to an object or a JSON string, and importing it back later.
// Using objects
const state = undoManager.exportState();
undoManager.importState(state);
// Using JSON strings
const json = undoManager.serializeState();
undoManager.deserializeState(json);You can register a command factory with a name, allowing you to execute commands using a string identifier instead of passing object instances.
undoManager.registerCommand('add', (val) => new AddNumberCommand(val));
// Later execute by name
undoManager.execute('add', 5);Initialize a new Oops instance with custom configuration options to control history behavior.
new Oops({
maxStackSize: 100,
snapshotInterval: 5,
compressThreshold: 50,
mergeWindow: 500
});