Oops.js

repository·master·Indexed 20 days ago

https://github.com/heyputer/oops.js

An 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.

Tokens
3.3K
Snippets
20
Records
20
Agent score
19%

What's inside @heyputer/oops.js

  1. Use Oops.js via CDN

    master

    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>
  2. Group commands using Transactions

    master

    Transactions allow you to group multiple commands so they are treated as a single atomic unit in the undo/redo history.

    1. Call beginTransaction() to start a group.
    2. Call execute() for each command you want in the group. These commands are held in a temporary buffer.
    3. Call 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.
    4. Call 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();
    }
  3. Initialize the Oops class

    master

    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
    });
  4. Implement undo/redo with the Command Pattern

    master

    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: 8
  5. Check undo/redo availability with canUndo and canRedo

    master

    Use 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;
    }
  6. Use CompositeCommand to group sub-commands

    master

    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);
  7. Manage transactions for atomic operations

    master

    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();
  8. Export and Import undo/redo state

    master

    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);
  9. Register and use string-based commands

    master

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