Backbone.Undo.js/README.md

144 lines
5.3 KiB
Markdown
Raw Normal View History

2013-05-27 23:57:31 +08:00
Backbone.Undo.js
================
An extremely simple Undo-Manager for Backbone.js
### Advantages of Backbone.Undo.js
2013-05-28 04:58:14 +08:00
* Easy to include and exclude
2013-05-28 04:57:27 +08:00
In comparison to other Backbone-based undo-managers like *memento*, you don't have to modify your models
or collections to use Backbone.Undo.js. You can have your whole application already set up with all the
models and collections and then add the undo-manager. That makes it easy to not only include
2013-05-28 04:58:14 +08:00
Backbone.Undo.js, but also to remove it again if you don't longer want to use it at some point.
* Uses Backbone-Events
2013-05-28 04:57:27 +08:00
To detect an action, Backbone.Undo.js listens to the events Backbone triggeres automatically. You don't have
to do anything. You don't have to `store()` or `restore()` certain states. Nothing.
* Memory-friendly
2013-05-28 02:29:23 +08:00
Backbone.Undo.js only stores changes, instead of snapshots (clones of models/collections).
2013-05-28 04:57:27 +08:00
* Optimized for Usability
2013-05-28 04:57:27 +08:00
In a sophisticated webapp one click of the user might trigger several Backbone-Events which are stored as
several Undo-Actions within the Undo-Stack. If the user then calls `undo()` it shouldn't just undo the latest
action, it should undo all the actions which were triggered by the user's click. Backbone.Undo.js has a way to
figure out which actions belong together and then undoes/redoes all of them.
## Getting started
2013-05-28 04:57:27 +08:00
Like with all the other JavaScript-Libraries you only need to include Backbone.Undo.js into your webpage or webapp
to make it available.
As Backbone.Undo.js depends on Backbone you need Backbone, which again depends on underscore.js (or lowdash.js) and
jQuery (or zepto). Make sure to include all these files before Backbone.Undo.js as it relies on these libraries:
<script src="jquery.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>
<!-- Backbone.Undo.js is included *after* those other libs -->
<script src="Backbone.Undo.js"></script>
### Backbone Version
Backbone.Undo.js was developed for Backbone 1.0.0 or higher.
### Underscore Version
Backbone.Undo.js was developed for Underscore 1.4.4 or higher.
# Setting up your UndoManager
In order to set up you UndoManager you have to do the following steps:
// 1. Instantiate your UndoManager
var myUndoManager = new Backbone.UndoManager({
maximumStackLength: 100 // maximumStackLength determines how many actions
// are stored to be undone. Default is Infinity aka no limit at all. This
// attribute is optional. You don't need to pass anything to the constructor.
});
// 2. Register the models and collections you want to observe
var model = new Backbone.Model,
collection = new Backbone.Collection;
myUndoManager.register(model, collection); // You can pass several objects as arguments
// You can setting up your objects here. Changes won't be tracked yet.
model.set("foo", "bar");
collection.add([{"something": "blue"}]);
// These changes can't be undone.
// 3. Start tracking the changes
myUndoManager.startTracking(); // Everything that happens from now on, can be undone
2013-05-28 04:57:27 +08:00
# Undo or Redo Actions
To undo the last set of actions, just call `undo()`
myUndoManager.undo();
To redo undone actions, call `redo()`
2013-05-28 04:57:27 +08:00
myUndoManager.redo();
2013-05-28 04:57:27 +08:00
### Problems that may occur
Backbone.Undo.js is not made to be called within your code. It has an internal mechanism which figures out
which Undo-Actions were generated in the same call cycle.
This mechanism is great for usability (see above, *Advantages of Backbone.Undo.js*). However this mechanism
makes it impossible to call `undo()` or `redo()` within a codeblock. Imagine this:
model.get("foo"); // "bar"
// Several changes:
model.set("foo", "baz");
model.set("foo", "qux");
model.set("foo", 42);
model.set("foo", {})
// One call to `undo`:
myUndoManager.undo();
model.get("foo"); // Is "bar" instead of 42
Calling `undo()` resets `"foo"` to `"bar"` instead of `42`, because it had figured out that the four `set`s happened in
one call cycle.
If you want to call `undo()` within your code and each time only want to undo the latest change you have to call the
changes to the model asynchronously.
model.get("foo");
// Several changes:
_.defer(function () {
model.set("foo", "baz");
_.defer(function () {
model.set("foo", "qux");
_.defer(function () {
model.set("foo", 42);
_.defer(function () {
model.set("foo", {});
myUndoManager.undo();
model.get("foo") // 42
myUndoManager.undo();
model.get("foo") // "qux"
myUndoManager.undo();
model.get("foo") // "baz"
myUndoManager.undo();
model.get("foo") // "bar"
})
})
})
})
2013-05-28 04:57:27 +08:00
Obviously noone would ever do that. In fact you also shouldn't do that: Your webapp shouldn't have any reference to the
undo-manager within your code. Try to develop it independently from the undo-manager.