forked from SE7ENSKY/UndoRedoer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
UndoRedoer.js
130 lines (114 loc) · 3.79 KB
/
UndoRedoer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Generated by CoffeeScript 1.6.3
/*!
* UndoRedoer
* @description Simple and robust CoffeeScript/JavaScript library for undo/redo features on plain state object. Full test coverage. For Node.JS and Browser (with AMD support).
* @author Se7enSky studio <[email protected]>
* @url http://www.se7ensky.com/
* @version 1.2.4
* @repository https://github.com/Se7enSky/UndoRedoer
* @license MIT
*/
;
(function(root, factory) {
if (typeof exports === 'object') {
return module.exports = factory(require('lodash'));
} else if (typeof define === 'function' && define.amd) {
return define(['lodash'], factory);
} else {
return root.returnExports = factory(root._);
}
})(this, function(_) {
var UndoRedoer;
return UndoRedoer = (function() {
function UndoRedoer(state, changes) {
this.state = state != null ? state : {};
this.changes = changes != null ? changes : [];
this.resetCursor();
this.reverseChanges = [];
}
UndoRedoer.prototype.pushChanges = function(change) {
var reverseChange;
this.changes.push(change);
reverseChange = this.mergeChange(this.state, change);
this.reverseChanges.push(reverseChange);
return this.resetCursor();
};
UndoRedoer.prototype.undo = function() {
var reverseChange;
if (!this.canUndo()) {
throw new Error('undo is disabled');
}
reverseChange = this.reverseChanges[this.cursor - 1];
this.mergeChange(this.state, reverseChange);
this.cursor--;
return reverseChange;
};
UndoRedoer.prototype.redo = function() {
var forwardChange;
if (!this.canRedo()) {
throw new Error('redo is disabled');
}
forwardChange = this.changes[this.cursor];
this.mergeChange(this.state, forwardChange);
this.cursor++;
return forwardChange;
};
UndoRedoer.prototype.canUndo = function() {
return this.cursor > 0;
};
UndoRedoer.prototype.canRedo = function() {
return this.cursor < this.changes.length;
};
UndoRedoer.prototype.dirty = function() {
return this.cursor < this.changes.length;
};
UndoRedoer.prototype.clearRedo = function() {
return this.changes.splice(this.cursor, this.changes.length - this.cursor);
};
UndoRedoer.prototype.save = function() {
return this.clearRedo();
};
UndoRedoer.prototype.resetCursor = function() {
return this.cursor = this.changes.length;
};
/*
@param {Object} dst The destination object.
@param {Object} changes The source object.
@returns reverse change
*/
UndoRedoer.prototype.mergeChange = function(dst, change) {
var key, reverseChange, value, _ref;
reverseChange = {};
if (_(change).isObject() && typeof change !== 'function') {
for (key in change) {
value = change[key];
if (typeof value === 'undefined') {
if (_(dst).has(key)) {
reverseChange[key] = dst[key];
delete dst[key];
} else {
}
} else {
if (_(dst).has(key)) {
if ((_ref = typeof value) === 'boolean' || _ref === 'string' || _ref === 'number') {
reverseChange[key] = dst[key];
dst[key] = value;
} else if (_(value).isArray()) {
reverseChange[key] = _(dst[key]).clone();
dst[key] = _(value).clone();
} else if (_(value).isObject() && typeof value !== 'function') {
reverseChange[key] = this.mergeChange(dst[key], value);
} else {
}
} else {
reverseChange[key] = void 0;
dst[key] = _(value).clone();
}
}
}
}
return reverseChange;
};
return UndoRedoer;
})();
});