All Projects → agrinko → js-undo-manager

agrinko / js-undo-manager

Licence: MIT license
Simple JavaScript undo/redo command manager supporting transactions with no dependencies

Programming Languages

javascript
184084 projects - #8 most used programming language
HTML
75241 projects
CSS
56736 projects

Projects that are alternatives of or similar to js-undo-manager

Regret
[Moved to MavenCentral] An undo-redo Android library which works with any objects and with an easy implementation. Perfect for drawing, text and photo editing apps.
Stars: ✭ 65 (+182.61%)
Mutual labels:  undo-redo, redo, undo
UndoRedo.js
A powerful and simple JavaScript library provides a history for undo/redo functionality. Just like a time machine! 🕐
Stars: ✭ 19 (-17.39%)
Mutual labels:  undo-redo, redo, undo
actions
Software without side-effects. Redo and Undo.
Stars: ✭ 23 (+0%)
Mutual labels:  undo-redo, redo, undo
zundo
🍜 undo/redo middleware for zustand
Stars: ✭ 170 (+639.13%)
Mutual labels:  redo, undo
undo
A undo-redo library.
Stars: ✭ 38 (+65.22%)
Mutual labels:  redo, undo
Redux Undo
♻️ higher order reducer to add undo/redo functionality to redux state containers
Stars: ✭ 2,744 (+11830.43%)
Mutual labels:  redo, undo
undox
⎌ Redux Implementation of Undo/Redo based on storing actions instead of states.
Stars: ✭ 25 (+8.7%)
Mutual labels:  redo, undo
rundo
Rundo is a undo redo library for rust which can auto generate undo op
Stars: ✭ 32 (+39.13%)
Mutual labels:  redo, undo
trans-dsl
a transaction model framework, seems simple but powerful
Stars: ✭ 64 (+178.26%)
Mutual labels:  transaction
web trader
📊 Python Flask game that consolidates data from Nasdaq, allowing the user to practice buying and selling stocks.
Stars: ✭ 21 (-8.7%)
Mutual labels:  transaction
KuiBaDB
Another OLAP database
Stars: ✭ 297 (+1191.3%)
Mutual labels:  transaction
LocalTransactionTableTest
利用rabbitmq做消息队列,通过本地消息事务表序列化消息,通过定时轮训保证消息强行落地,最终达到数据最终一致性
Stars: ✭ 19 (-17.39%)
Mutual labels:  transaction
node-pg-large-object
Large object support for PostgreSQL clients using the node-postgres library.
Stars: ✭ 31 (+34.78%)
Mutual labels:  transaction
Apriori-and-Eclat-Frequent-Itemset-Mining
Implementation of the Apriori and Eclat algorithms, two of the best-known basic algorithms for mining frequent item sets in a set of transactions, implementation in Python.
Stars: ✭ 36 (+56.52%)
Mutual labels:  transaction
SimpleCoin
A simple cryptocurrency application for educational purposes only.
Stars: ✭ 13 (-43.48%)
Mutual labels:  transaction
orchestrate-node
This Orchestrate library provides convenient access to the Orchestrate API from applications written in server-side NodeJS
Stars: ✭ 19 (-17.39%)
Mutual labels:  transaction
rlp
Recursive Length Prefix Encoding in PHP.
Stars: ✭ 25 (+8.7%)
Mutual labels:  transaction
blockchain-pen
BlockchainPen - a web app for writing immutable messages to the blockchain.
Stars: ✭ 14 (-39.13%)
Mutual labels:  transaction
arweave-python-client
This client allows you to integrate your python apps with the Arweave network allowing you to perform wallet operations and transactions
Stars: ✭ 87 (+278.26%)
Mutual labels:  transaction
indexeddb-orm
Indexed DB ORM
Stars: ✭ 53 (+130.43%)
Mutual labels:  transaction

JS Undo Manager

Simple JavaScript undo/redo command manager supporting transactions with no dependencies

Get more power into your app by controlling its execution process. Structurize your code with distinct and isolated commands. Enhance users experience by letting them use good old Ctrl+Z!

Features

  • No dependencies!
  • Simple API to control execution
  • OOP-style (JSUndoManager class with settings hash in constructor)
  • Transactions support (executing several actions in a batch)
  • Out-of-box binding to Ctrl+Z, Ctrl+Y and Ctrl+Shift+Z hot keys for simplest use-cases
  • Source code in 3 samples: ES 2015, ES 5.1 and ES 5.1 minified
  • Importing via AMD, CommonJS or global object
  • Fully tested

Examples

Script can be imported either via AMD, CommonJS or global object. Below are some examples of different kinds of import and usage.

With global-object method refer to JSUndoManager class name, though you can always alias it yourself with a simpler name.

Note! Some browsers support redo and undo by default in inputs when pressing ctrl+z & ctrl+y. If you want to process them in a more flexible way and bind undo & redo actions to these shortcuts, don't forget to prevent default browser's behaviour.

Demo

Download the repo folder and open demo.html in your browser.

It uses some self-explaining examples to demonstrate the script's abilities.

Basic usage

Example of usage in code (assuming you have imported the source file before running this):

// CommonJS style
var UndoManager = require("js-undo-manager");

var um = new UndoManager();
var i = 0;

um.execute(increment, decrement); // `increment` will be executed right off
console.log(i); // i == 1

um.undo();
console.log(i); // i == 0

um.redo();
console.log(i); // i == 1

function increment() { i++; }
function decrement() { i--; }

Transactions example

Example of transactions:

// Global object
var undoManager = new JSUndoManager();
var i = 0;

// successful transaction example
undoManager.transaction.begin();
undoManager.execute(increment, decrement);
undoManager.execute(increment, decrement);
console.log(i); // i == 2

undoManager.transaction.end();
undoManager.undo();
console.log(i); // i == 0

undoManager.redo();
console.log(i); // i == 2

// canceled transaction example
undoManager.transaction.begin();
undoManager.execute(increment, decrement);
undoManager.execute(increment, decrement);
console.log(i); // i == 4

undoManager.transaction.cancel(); // revert and forget commands executed during transaction
console.log(i); // i == 2
console.log(`Stack size: ` + undoManager.getSize()); // stack size is 1

undoManager.undo();
console.log(i); // i == 0

function increment() { i++; }
function decrement() { i--; }

The "record" method

JS Undo Manager supports 2 methods for recording your commands: execute and record. The example of the former is given above. The latter works same way but doesn't execute the command right off - it assumes it's been already executed before being recorded.

An example of when record function might come in handy is when using events callbacks. When a user entered some text into an input, browser updates its text automatically. You just subscribe to the input's change event and record the change. When user un-does and re-does this action, the input's content should be updated programmatically. See example below:

// Using global variable
var UM = window.JSUndoManager; // you can give any simple name to the class
var um = new UM({
  limit: 50, // limit of the history stack
  debug: true
});

var input = document.getElementById(`some-input`);
var prevValue = input.value; // way to know previous value after `change` event

input.addEventListener(`change`, function() {
    // these variables are stuck in the function's closure and used repeatedly by 'redo' and 'undo' functions
    var prev = prevValue;
    var value = input.value;

    prevValue = value; // update prevValue for the next time

    um.record({
        redo: function() {
            input.value = value;
            // update previous value manually because we don't trigger `change` event here
            prevValue = value;
        },
        undo: function() {
            input.value = prev;
            prevValue = prev;
        }
    });
});

Installation

Using npm

npm install agrinko/js-undo-manager --save

Then in your JS code:

require("js-undo-manager")

This will require minified file as a dependency.

It's assumed to work with both CommonJS or AMD, but needs to be tested. Please communicate if you confirm.

Using yarn

yarn add agrinko/js-undo-manager

Rest is the same as with npm.

Simple download

Download one of the versions from src directory (either EcmaScript 6 full, EcmaScript 5 full or EcmaScript 5 minified).

Attach the script anywhere on your page.

Repository

If you want to contribute or research the repo, clone it and run yarn install (read more on how to download and install yarn). You can also use npm install for quick testing if you're not going to commit changes.

Run yarn build each time you want to compile and minify ES6 source code.

Run yarn test to compile ES6 test files and run them in PhantomJS. Only after that you can open test/index.html in browser to check results there.

API

Settings

limit: number

Default: 100

Maximum size of the commands stack.

When commands stack reaches this number, with each new command, the oldest commands are cut off and forgotten, meaning you cannot undo them any more.

This value affects memory usage and can be adjusted in a wide range. It also can be updated dynamically after the command manager was initialized. Read more about setLimit method below.

debug: boolean

Default: false

Whether to emit execution status in console.

When turned on, Command Manager will log messages when recording commands, executing, undoing and redoing, etc.

bindHotKeys: boolean

Default: false

Whether to bind undo and redo commands to Ctrl+Z, Ctrl+Y & Ctrl+Shift+Z hot keys.

It is generally used for quick testing when you don't want to write document.onkeydown event handler manually. For more advanced and flexible usage of hot keys this option should be turned off and replaced with a custom implementation.

useTransactions: boolean

Default: true

Whether to initialize TransactionManager.

Turning this off might give some very slight increase in performance, if you are sure you're not going to use transactions.

By default working with transactions is performed via commandManager.transaction reference, but it will be undefined if this setting is turned off.

Methods

Most method are designed to be used in chain by returning this each time, e.g:

commandManager.setLimit(55).undo().undo();

record({redo: Function, undo: Function}): JSUndoManager

Alternative API: record(Function, Function): JSUndoManager

Record the command containing redo and undo functions.

With alternative API the first argument refers to redo and the second - to undo function.

Unlike with execute method, no functions are executed when calling record. See an example of when it might come in handy in the "record" method section above.

execute({redo: Function, undo: Function}): JSUndoManager

Alternative API: execute(Function, Function): JSUndoManager

Record the command containing redo and undo functions and execute the redo function immediately.

See examples of usage above in the examples section.

undo(): JSUndoManager

Undo the last executed command by calling its undo function.

Performs no operation if there is nothing to undo.

redo(): JSUndoManager

Redo the last "undone" command by calling its redo function.

Performs no operation if there is nothing to redo.

setLimit(number): JSUndoManager

Change stack size limit initially defined in the constructor options. Read more in limit setting description.

If there are currently more commands in history stack than the specified number, extra oldest ones will be removed and forgotten.

If there are currently more commands than the specified number that can be re-done with redo method, stack size will not be changed and a warning will be emitted in console. We can't cut commands from stack that are above the stack pointer (we only cut from tail).

reset(): JSUndoManager

Reset history stack entirely. The manager comes back to its initial state.

bindHotKeys(): JSUndoManager

Bind undo and redo commands to Ctrl+Z, Ctrl+Y & Ctrl+Shift+Z hot keys.

Read more in bindHotKeys setting description above.

It can be called to bind the event handler dynamically when bindHotKeys setting was not set initially.

canUndo(): boolean

Check whether undoing is possible (i.e. if there is any command to undo).

canRedo(): boolean

Check whether redoing is possible (i.e. if there is any command to redo).

getSize(): number

Get number of commands in the history stack.

isEmpty(): boolean

Check whether the stack is empty.

isFull(): boolean

Check whether the stack is full (i.e. its size has reached the limit).

Transactions

TransactionManager class is an extension over the JSUndoManager. It can be turned off by setting useTransactions: false in the constructor (read more above).

Interaction with transactions is performed via commandManager.transaction reference (assuming "commandManager" is an instance of JSUndoManager). See transactions example section above.

Note that transaction is recorded by Undo Manager only after calling its end method. If you execute undo method while transaction is in progress, its commands won't be affected since they are stored separately. Instead, previous commands will be undone. Only after you finish the transaction it will be possible to undo it in a batch.

transaction.begin(): void

Set state of transaction to "in progress".

All the following commands will not be directly recorded in history stack but rather remembered in a transaction's sequence array.

Running this method when a transaction is already in progress doesn't make any change.

transaction.end(): void

Finish the transaction successfully.

All the transaction's commands are packed together in a sequence and recorded by JSUndoManager as a single command.

Running this method when there is no transaction in progress doesn't make any change.

transaction.cancel(): void

Cancel the transaction.

All the commands executed during the transaction are reverted by calling their undo functions in a reverse order. No command is recorded by JSUndoManager.

Running this method when there is no transaction in progress doesn't make any change.

transaction.isInProgress(): boolean

Check whether there is a transaction in progress currently.

transaction.isPending(): boolean

Check if there is no transaction in progress currently.

The opposite of transaction.isInProgress().

TODO

  • upload a plugin supporting js-undo-manager in BackboneJS
  • set up code coverage
  • extend transactions usage by using labels, etc.
  • support events and/or callbacks for interaction
  • limit transactions's sequence array (?)

Alexey Grinko, 2017 (c)

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].