commandz 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +137 -18
- data/commandz.min.js +3 -3
- data/lib/assets/javascripts/commandz.coffee +80 -30
- data/lib/commandz/version.rb +1 -1
- data/spec/commandz_spec.coffee +91 -21
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 706f3e28800a1bd1c1e659a2fcf7a355c8b03fab
|
4
|
+
data.tar.gz: 4b3451066e237bbf6e4c75e8245f9ac1e528a490
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2caf799f9bab92f94978984affae1337d23acb9dba7f4476d3a55637a5ed810e60d08ce08ba4c708b7251f0d5df24e65c2b6ea61f4bf43d69891bf9850ecb35
|
7
|
+
data.tar.gz: aa1ddb7d6a90db28f177d10b24eac586e94dfc16eea054ed29aa372d30d3d9dbdf609e8a9a5c42f03ee44079991efa6737f6840372f185814d858d5b011951aa
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## [v0.1.0](https://github.com/EtienneLem/commandz/tree/v0.1.0)
|
2
|
+
- Rename `CommandZ.commands` -> `CommandZ.history`
|
3
|
+
- Rename `CommandZ.onChange` -> `CommandZ.onStatusChange`
|
4
|
+
- Add storage with threshold support
|
5
|
+
- Add `CommandZ.reset()`
|
6
|
+
|
1
7
|
## [v0.0.3](https://github.com/EtienneLem/commandz/tree/v0.0.3)
|
2
8
|
- Fix a bug where `handleChange` wouldn’t be called after `CommandZ.execute()`
|
3
9
|
|
data/README.md
CHANGED
@@ -16,14 +16,19 @@
|
|
16
16
|
|
17
17
|
## Table of contents
|
18
18
|
- [API](#api)
|
19
|
-
- [
|
20
|
-
- [
|
21
|
-
- [
|
22
|
-
- [
|
23
|
-
- [
|
24
|
-
- [
|
25
|
-
- [
|
19
|
+
- [execute](#execute) | [store](#store)
|
20
|
+
- [undo (commands)](#undo-commands) | [undo (storage)](#undo-storage)
|
21
|
+
- [redo (commands)](#redo-commands) | [redo (storage)](#redo-storage)
|
22
|
+
- [setThreshold (storage only)](#setthreshold-storage-only)
|
23
|
+
- [status](#status)
|
24
|
+
- [onStatusChange](#onstatuschange)
|
25
|
+
- [onStorageChange](#onstoragechange)
|
26
|
+
- [clear](#clear)
|
27
|
+
- [reset](#reset)
|
28
|
+
- [keyboardShortcuts](#keyboardshortcuts)
|
26
29
|
- [DOM Example](#dom-example)
|
30
|
+
- [Commands](#commands)
|
31
|
+
- [Storage](#storage)
|
27
32
|
- [Setup](#setup)
|
28
33
|
- [Rails](#rails)
|
29
34
|
- [Other](#other)
|
@@ -39,8 +44,9 @@ COMMAND: {
|
|
39
44
|
}
|
40
45
|
```
|
41
46
|
|
42
|
-
### execute
|
43
|
-
Receive `COMMAND` or `COMMANDS` and execute `COMMAND.up()
|
47
|
+
### #execute
|
48
|
+
Receive `COMMAND` or `COMMANDS` and execute `COMMAND.up()`.<br>
|
49
|
+
Store commands as a `{ command: COMMAND }` object in the history array.
|
44
50
|
|
45
51
|
**Single command per history item**<br>
|
46
52
|
Store one history item per `COMMAND`.
|
@@ -79,8 +85,8 @@ console.log(CommandZ.commands.length) // => 1
|
|
79
85
|
console.log(CommandZ.index) // => 0
|
80
86
|
```
|
81
87
|
|
82
|
-
### undo
|
83
|
-
Call `COMMAND.down()` and set the index to the previous
|
88
|
+
### #undo (commands)
|
89
|
+
Call `COMMAND.down()` and set the index to the previous history item.
|
84
90
|
|
85
91
|
```js
|
86
92
|
CommandZ.execute({
|
@@ -104,8 +110,8 @@ console.log(CommandZ.commands.length) // => 2
|
|
104
110
|
console.log(CommandZ.index) // => -1
|
105
111
|
```
|
106
112
|
|
107
|
-
### redo
|
108
|
-
Set the index to the next
|
113
|
+
### #redo (commands)
|
114
|
+
Set the index to the next history item and call `COMMAND.up()`.
|
109
115
|
|
110
116
|
```js
|
111
117
|
CommandZ.execute({
|
@@ -125,7 +131,73 @@ console.log(CommandZ.commands.length) // => 2
|
|
125
131
|
console.log(CommandZ.index) // => 0
|
126
132
|
```
|
127
133
|
|
128
|
-
###
|
134
|
+
### #store
|
135
|
+
Store data as a `{ data: … }` object in the history array.
|
136
|
+
|
137
|
+
```js
|
138
|
+
CommandZ.store({ width: 100, height: 100 })
|
139
|
+
```
|
140
|
+
|
141
|
+
### #undo (storage)
|
142
|
+
Set the index to the previous history item and send data via [`CommandZ.onStorageChange`](#onstoragechange).
|
143
|
+
|
144
|
+
```js
|
145
|
+
CommandZ.onStorageChange(function(data) {
|
146
|
+
console.log(data)
|
147
|
+
})
|
148
|
+
|
149
|
+
CommandZ.store({ width: 100, height: 100 })
|
150
|
+
CommandZ.undo()
|
151
|
+
|
152
|
+
console.log(CommandZ.commands.length) // => 1
|
153
|
+
console.log(CommandZ.index) // => -1
|
154
|
+
|
155
|
+
CommandZ.store({ width: 100, height: 100 })
|
156
|
+
CommandZ.store({ width: 200, height: 200 })
|
157
|
+
CommandZ.undo() # => { width: 100, height: 100 }
|
158
|
+
|
159
|
+
console.log(CommandZ.commands.length) // => 2
|
160
|
+
console.log(CommandZ.index) // => 0
|
161
|
+
```
|
162
|
+
|
163
|
+
### #redo (storage)
|
164
|
+
Set the index to the next history item and send data via [`CommandZ.onStorageChange`](#onstoragechange).
|
165
|
+
|
166
|
+
```js
|
167
|
+
CommandZ.onStorageChange(function(data) {
|
168
|
+
console.log(data)
|
169
|
+
})
|
170
|
+
|
171
|
+
CommandZ.store({ width: 100, height: 100 })
|
172
|
+
CommandZ.store({ width: 200, height: 200 })
|
173
|
+
CommandZ.undo() # => { width: 100, height: 100 }
|
174
|
+
CommandZ.redo() # => { width: 200, height: 200 }
|
175
|
+
|
176
|
+
console.log(CommandZ.commands.length) // => 2
|
177
|
+
console.log(CommandZ.index) // => 1
|
178
|
+
```
|
179
|
+
|
180
|
+
### #setThreshold (storage only)
|
181
|
+
Unlike commands, you can allow your users to spam the `CMD+Z` button without restoring every states at every steps.<br>
|
182
|
+
Threshold is set in `milliseconds`.
|
183
|
+
|
184
|
+
```js
|
185
|
+
CommandZ.setThreshold(500)
|
186
|
+
CommandZ.onStorageChange(function(data) {
|
187
|
+
console.log(data)
|
188
|
+
})
|
189
|
+
|
190
|
+
CommandZ.store({ width: 100, height: 100 })
|
191
|
+
CommandZ.store({ width: 200, height: 200 })
|
192
|
+
CommandZ.store({ width: 300, height: 300 })
|
193
|
+
|
194
|
+
CommandZ.undo(100)
|
195
|
+
|
196
|
+
// Wait 500ms
|
197
|
+
// => { width: 100, height: 100 }
|
198
|
+
```
|
199
|
+
|
200
|
+
### #status
|
129
201
|
Return the current status.
|
130
202
|
|
131
203
|
```js
|
@@ -144,11 +216,11 @@ console.log(CommandZ.commands.length) // => 2
|
|
144
216
|
console.log(CommandZ.index) // => 1
|
145
217
|
```
|
146
218
|
|
147
|
-
###
|
219
|
+
### #onStatusChange
|
148
220
|
Register a callback that will be called with the `status` every time there’s a change to the history.
|
149
221
|
|
150
222
|
```js
|
151
|
-
CommandZ.
|
223
|
+
CommandZ.onStatusChange(function(status) {
|
152
224
|
console.log(status)
|
153
225
|
})
|
154
226
|
|
@@ -166,7 +238,21 @@ CommandZ.undo() // => { canUndo: true, canRedo: true }
|
|
166
238
|
CommandZ.undo() // => { canUndo: false, canRedo: true }
|
167
239
|
```
|
168
240
|
|
169
|
-
###
|
241
|
+
### #onStorageChange
|
242
|
+
Register a callback that will be called with the `data` on undo/redo.
|
243
|
+
|
244
|
+
```js
|
245
|
+
CommandZ.onStorageChange(function(data) {
|
246
|
+
console.log(data)
|
247
|
+
})
|
248
|
+
|
249
|
+
CommandZ.store({ width: 100, height: 100 })
|
250
|
+
CommandZ.store({ width: 200, height: 200 })
|
251
|
+
|
252
|
+
CommandZ.undo() // => { width: 100, height: 100 }
|
253
|
+
```
|
254
|
+
|
255
|
+
### #clear
|
170
256
|
Clear history.
|
171
257
|
|
172
258
|
```js
|
@@ -187,7 +273,10 @@ console.log(CommandZ.commands.length) // => 0
|
|
187
273
|
console.log(CommandZ.index) // => -1
|
188
274
|
```
|
189
275
|
|
190
|
-
###
|
276
|
+
### #reset
|
277
|
+
Clear history, remove callbacks and set threshold to 0.
|
278
|
+
|
279
|
+
### #keyboardShortcuts
|
191
280
|
Enable or disable `CMD+Z` & `CMD+SHIFT+Z` keyboard shortcuts. These shortcuts are enabled by default.<br>
|
192
281
|
Will only `undo()` & `redo()` if the current selected element is not an input so that it doesn’t prevent your OS default behavior.
|
193
282
|
|
@@ -197,6 +286,7 @@ CommandZ.keyboardShortcuts(false)
|
|
197
286
|
```
|
198
287
|
|
199
288
|
## DOM Example
|
289
|
+
### Commands
|
200
290
|
```js
|
201
291
|
// This example requires jQuery or Zepto
|
202
292
|
$container = $('<div></div>')
|
@@ -234,6 +324,35 @@ console.log(CommandZ.commands.length) // => 3
|
|
234
324
|
console.log(CommandZ.index) // => 2
|
235
325
|
```
|
236
326
|
|
327
|
+
### Storage
|
328
|
+
```js
|
329
|
+
// This example requires jQuery or Zepto
|
330
|
+
$container = $('<div></div>')
|
331
|
+
|
332
|
+
img = new Image
|
333
|
+
$container.html(img)
|
334
|
+
|
335
|
+
// Register undo/redo callback
|
336
|
+
CommandZ.onStorageChange = function(data) {
|
337
|
+
img.width = data.width
|
338
|
+
img.height = data.height
|
339
|
+
}
|
340
|
+
|
341
|
+
img.width = 100
|
342
|
+
img.height = 100
|
343
|
+
|
344
|
+
// Lets store some states
|
345
|
+
[1, 2, 3, 4].forEach(function(i) {
|
346
|
+
CommandZ.store({ width: i * 100, height: i * 100 })
|
347
|
+
})
|
348
|
+
|
349
|
+
CommandZ.undo(2)
|
350
|
+
console.log(img.width) // => 200
|
351
|
+
|
352
|
+
CommandZ.redo()
|
353
|
+
console.log(img.width) // => 300
|
354
|
+
```
|
355
|
+
|
237
356
|
## Setup
|
238
357
|
### Rails
|
239
358
|
1. Add `gem 'commandz'` to your Gemfile.
|
data/commandz.min.js
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
/*
|
2
|
-
* CommandZ v0.0
|
2
|
+
* CommandZ v0.1.0
|
3
3
|
* https://github.com/EtienneLem/commandz
|
4
4
|
*
|
5
5
|
* Copyright 2013, Etienne Lemay http://heliom.ca
|
6
6
|
* Released under the MIT license
|
7
7
|
*
|
8
|
-
* Date: 2013-
|
8
|
+
* Date: 2013-09-02 11:47:04 -0400
|
9
9
|
*/
|
10
|
-
(function(){var t,
|
10
|
+
(function(){var t,e=function(t,e){return function(){return t.apply(e,arguments)}};t=function(){function t(){this.handleKeypress=e(this.handleKeypress,this),this.VERSION="0.1.0",this.reset(),this.keyboardShortcuts(!0)}return t.prototype.reset=function(){return this.clear(),this.statusChangeCallback=null,this.storageChangeCallback=null,this.thresholdTimer=null,this.threshold=0},t.prototype.clear=function(){return this.history=[],this.index=-1},t.prototype.keyboardShortcuts=function(t){var e;return null==t&&(t=!0),e=t?"addEventListener":"removeEventListener",document[e]("keypress",this.handleKeypress)},t.prototype.handleKeypress=function(t){return"INPUT"!==document.activeElement.nodeName&&122===t.keyCode&&t.metaKey===!0?(t.preventDefault(),t.shiftKey?this.redo():this.undo()):void 0},t.prototype.execute=function(t){var e;return e={},e.command=t,this.up(t),this.addToHistory(e)},t.prototype.store=function(t){var e;return e={},e.data=t,this.addToHistory(e)},t.prototype.addToHistory=function(t){var e;return this.index<this.history.length-1&&(e=this.history.length-this.index-1,this.history.splice(-e)),this.history.push(t),this.index=this.history.length-1,this.handleStatusChange()},t.prototype.undo=function(t){var e,n,s,i,h;if(null==t&&(t=1),this.status().canUndo)for(i=h=1;t>=1?t>=h:h>=t;i=t>=1?++h:--h){if(!this.history[this.index])return;s=this.history[this.index],(e=s.command)&&this.down(e),this.index--,(s=this.history[this.index])&&(n=s.data)&&this.handleData(n),this.handleStatusChange()}},t.prototype.redo=function(t){var e,n,s,i,h;if(null==t&&(t=1),this.status().canRedo)for(i=h=1;t>=1?t>=h:h>=t;i=t>=1?++h:--h){if(!this.history[this.index+1])return;this.index++,s=this.history[this.index],(e=s.command)&&this.up(e),(n=s.data)&&this.handleData(n),this.handleStatusChange()}},t.prototype.exec=function(t,e){var n,s,i,h;if(!(e instanceof Array))return e[t]();for(h=[],s=0,i=e.length;i>s;s++)n=e[s],h.push(n[t]());return h},t.prototype.up=function(t){return this.exec("up",t)},t.prototype.down=function(t){return this.exec("down",t)},t.prototype.handleData=function(t){var e=this;return this.threshold>0?(clearTimeout(this.thresholdTimer),this.thresholdTimer=setTimeout(function(){return e.sendData(t)},this.threshold)):this.sendData(t)},t.prototype.sendData=function(t){return this.storageChangeCallback?this.storageChangeCallback(t):void 0},t.prototype.onStorageChange=function(t){return this.storageChangeCallback=t},t.prototype.setThreshold=function(t){return this.threshold=t},t.prototype.onStatusChange=function(t){return this.statusChangeCallback=t,this.handleStatusChange()},t.prototype.handleStatusChange=function(){return this.statusChangeCallback?this.statusChangeCallback(this.status()):void 0},t.prototype.status=function(){return{canUndo:this.index>-1,canRedo:this.index<this.history.length-1}},t}(),this.CommandZ=new t}).call(this);
|
@@ -1,63 +1,94 @@
|
|
1
1
|
class CommandZ
|
2
2
|
|
3
3
|
constructor: ->
|
4
|
-
@VERSION = '0.0
|
5
|
-
@changeCallback = null
|
4
|
+
@VERSION = '0.1.0'
|
6
5
|
|
7
|
-
this.
|
6
|
+
this.reset()
|
8
7
|
this.keyboardShortcuts(true)
|
9
8
|
|
9
|
+
reset: ->
|
10
|
+
this.clear()
|
11
|
+
|
12
|
+
@statusChangeCallback = null
|
13
|
+
@storageChangeCallback = null
|
14
|
+
@thresholdTimer = null
|
15
|
+
@threshold = 0
|
16
|
+
|
10
17
|
clear: ->
|
11
|
-
@
|
18
|
+
@history = []
|
12
19
|
@index = -1
|
13
20
|
|
14
21
|
keyboardShortcuts: (enable=true) ->
|
15
22
|
addOrRemove = if enable then 'addEventListener' else 'removeEventListener'
|
16
|
-
document[addOrRemove]('keypress', this.
|
23
|
+
document[addOrRemove]('keypress', this.handleKeypress)
|
17
24
|
|
18
|
-
|
25
|
+
handleKeypress: (e) =>
|
19
26
|
return if document.activeElement.nodeName is 'INPUT'
|
20
27
|
return unless e.keyCode is 122 and e.metaKey is true
|
21
28
|
|
22
29
|
e.preventDefault()
|
23
30
|
if e.shiftKey then this.redo() else this.undo()
|
24
31
|
|
32
|
+
# Execute and store commands as { command: {up: ->, down: ->} }
|
25
33
|
execute: (command) ->
|
34
|
+
historyItem = {}
|
35
|
+
historyItem.command = command
|
36
|
+
|
26
37
|
this.up(command)
|
38
|
+
this.addToHistory(historyItem)
|
39
|
+
|
40
|
+
# Store data as { data: … }
|
41
|
+
store: (data) ->
|
42
|
+
historyItem = {}
|
43
|
+
historyItem.data = data
|
44
|
+
|
45
|
+
this.addToHistory(historyItem)
|
46
|
+
|
47
|
+
# History management
|
48
|
+
addToHistory: (historyItem) ->
|
49
|
+
# Overwrite upcoming history items
|
50
|
+
if @index < @history.length - 1
|
51
|
+
difference = (@history.length - @index) - 1
|
52
|
+
@history.splice(-difference)
|
27
53
|
|
28
|
-
|
29
|
-
|
30
|
-
difference = (@commands.length - @index) - 1
|
31
|
-
@commands.splice(-difference)
|
54
|
+
@history.push(historyItem)
|
55
|
+
@index = @history.length - 1
|
32
56
|
|
33
|
-
|
34
|
-
@commands.push(command)
|
35
|
-
@index = @commands.length - 1
|
36
|
-
this.handleChange()
|
57
|
+
this.handleStatusChange()
|
37
58
|
|
38
59
|
undo: (times=1) ->
|
39
60
|
return unless this.status().canUndo
|
40
61
|
|
41
62
|
for i in [1..times]
|
42
|
-
return unless @
|
63
|
+
return unless @history[@index]
|
43
64
|
|
44
|
-
|
65
|
+
historyItem = @history[@index]
|
66
|
+
this.down(command) if command = historyItem.command
|
67
|
+
|
68
|
+
# Has to be after a command item, but before a data item
|
45
69
|
@index--
|
46
70
|
|
47
|
-
|
71
|
+
if historyItem = @history[@index]
|
72
|
+
this.handleData(data) if data = historyItem.data
|
73
|
+
|
74
|
+
this.handleStatusChange()
|
48
75
|
|
49
76
|
redo: (times=1) ->
|
50
77
|
return unless this.status().canRedo
|
51
78
|
|
52
79
|
for i in [1..times]
|
53
|
-
return unless @
|
80
|
+
return unless @history[@index + 1]
|
54
81
|
|
82
|
+
# Has to be before both a command and a data item
|
55
83
|
@index++
|
56
|
-
this.up(@commands[@index])
|
57
84
|
|
58
|
-
|
85
|
+
historyItem = @history[@index]
|
86
|
+
this.up(command) if command = historyItem.command
|
87
|
+
this.handleData(data) if data = historyItem.data
|
59
88
|
|
60
|
-
|
89
|
+
this.handleStatusChange()
|
90
|
+
|
91
|
+
# Execute up/down action on a command
|
61
92
|
# command can be a group of commands or a single command
|
62
93
|
exec: (action, command) ->
|
63
94
|
return command[action]() unless command instanceof Array
|
@@ -66,19 +97,38 @@ class CommandZ
|
|
66
97
|
up: (command) -> this.exec('up', command)
|
67
98
|
down: (command) -> this.exec('down', command)
|
68
99
|
|
69
|
-
#
|
70
|
-
|
71
|
-
@
|
72
|
-
|
100
|
+
# Send current history item data
|
101
|
+
handleData: (data) ->
|
102
|
+
return this.sendData(data) unless @threshold > 0
|
103
|
+
|
104
|
+
clearTimeout(@thresholdTimer)
|
105
|
+
@thresholdTimer = setTimeout =>
|
106
|
+
this.sendData(data)
|
107
|
+
, @threshold
|
108
|
+
|
109
|
+
sendData: (data) ->
|
110
|
+
return unless @storageChangeCallback
|
111
|
+
@storageChangeCallback(data)
|
112
|
+
|
113
|
+
# Storage management
|
114
|
+
onStorageChange: (callback) ->
|
115
|
+
@storageChangeCallback = callback
|
116
|
+
|
117
|
+
setThreshold: (threshold) ->
|
118
|
+
@threshold = threshold
|
119
|
+
|
120
|
+
# Status management
|
121
|
+
onStatusChange: (callback) ->
|
122
|
+
@statusChangeCallback = callback
|
123
|
+
this.handleStatusChange()
|
73
124
|
|
74
|
-
|
75
|
-
return unless @
|
76
|
-
@
|
125
|
+
handleStatusChange: ->
|
126
|
+
return unless @statusChangeCallback
|
127
|
+
@statusChangeCallback(this.status())
|
77
128
|
|
78
|
-
# Return current status
|
79
129
|
status: ->
|
80
130
|
canUndo: @index > -1
|
81
|
-
canRedo: @index < @
|
131
|
+
canRedo: @index < @history.length - 1
|
82
132
|
|
83
133
|
# Singleton
|
84
134
|
@CommandZ = new CommandZ
|
data/lib/commandz/version.rb
CHANGED
data/spec/commandz_spec.coffee
CHANGED
@@ -1,39 +1,39 @@
|
|
1
1
|
describe 'CommandZ', ->
|
2
|
-
describe '
|
2
|
+
describe 'commands', ->
|
3
3
|
it 'stores commands', ->
|
4
4
|
[0..9].forEach (i) -> CommandZ.execute({up: (-> i), down: (-> i)})
|
5
5
|
|
6
|
-
expect(CommandZ.
|
6
|
+
expect(CommandZ.history.length).toBe(10)
|
7
7
|
expect(CommandZ.index).toBe(9)
|
8
8
|
|
9
9
|
it 'undo', ->
|
10
10
|
[0..3].forEach -> CommandZ.undo()
|
11
11
|
|
12
|
-
expect(CommandZ.
|
12
|
+
expect(CommandZ.history.length).toBe(10)
|
13
13
|
expect(CommandZ.index).toBe(5)
|
14
14
|
|
15
15
|
it 'redo', ->
|
16
16
|
CommandZ.redo()
|
17
17
|
|
18
|
-
expect(CommandZ.
|
18
|
+
expect(CommandZ.history.length).toBe(10)
|
19
19
|
expect(CommandZ.index).toBe(6)
|
20
20
|
|
21
21
|
it 'undo many times', ->
|
22
22
|
CommandZ.undo(3)
|
23
|
-
expect(CommandZ.
|
23
|
+
expect(CommandZ.history.length).toBe(10)
|
24
24
|
expect(CommandZ.index).toBe(3)
|
25
25
|
|
26
26
|
CommandZ.undo(100)
|
27
|
-
expect(CommandZ.
|
27
|
+
expect(CommandZ.history.length).toBe(10)
|
28
28
|
expect(CommandZ.index).toBe(-1)
|
29
29
|
|
30
30
|
it 'redo many times', ->
|
31
31
|
CommandZ.redo(3)
|
32
|
-
expect(CommandZ.
|
32
|
+
expect(CommandZ.history.length).toBe(10)
|
33
33
|
expect(CommandZ.index).toBe(2)
|
34
34
|
|
35
35
|
CommandZ.redo(100)
|
36
|
-
expect(CommandZ.
|
36
|
+
expect(CommandZ.history.length).toBe(10)
|
37
37
|
expect(CommandZ.index).toBe(9)
|
38
38
|
|
39
39
|
it 'returns current status', ->
|
@@ -46,47 +46,92 @@ describe 'CommandZ', ->
|
|
46
46
|
CommandZ.undo(3)
|
47
47
|
CommandZ.execute({up: (->), down: (->)})
|
48
48
|
|
49
|
-
expect(CommandZ.
|
49
|
+
expect(CommandZ.history.length).toBe(8)
|
50
50
|
expect(CommandZ.index).toBe(7)
|
51
51
|
|
52
52
|
it 'clears commands', ->
|
53
53
|
CommandZ.clear()
|
54
54
|
|
55
|
-
expect(CommandZ.
|
55
|
+
expect(CommandZ.history.length).toBe(0)
|
56
56
|
expect(CommandZ.index).toBe(-1)
|
57
57
|
|
58
58
|
it 'stores grouped commands', ->
|
59
59
|
CommandZ.execute([{up: (->), down: (->)}, {up: (->), down: (->)}])
|
60
|
-
CommandZ.undo()
|
61
|
-
CommandZ.redo()
|
62
60
|
|
63
|
-
expect(CommandZ.
|
64
|
-
expect(CommandZ.
|
61
|
+
expect(CommandZ.history.length).toBe(1)
|
62
|
+
expect(CommandZ.history[0].command.length).toBe(2)
|
65
63
|
|
66
64
|
expect(CommandZ.index).toBe(0)
|
67
65
|
|
68
|
-
it 'registers
|
66
|
+
it 'registers onStatusChange callback', ->
|
69
67
|
CommandZ.clear()
|
70
68
|
[0..2].forEach (i) -> CommandZ.execute({up: (-> i), down: (-> i)})
|
71
69
|
|
72
|
-
|
73
|
-
CommandZ.
|
70
|
+
onStatusChangeCallback = jasmine.createSpy('onStatusChangeCallback')
|
71
|
+
CommandZ.onStatusChange (status) -> onStatusChangeCallback('test')
|
74
72
|
|
75
73
|
CommandZ.undo(3)
|
76
74
|
CommandZ.redo(2)
|
77
75
|
CommandZ.execute({up: (->), down: (->)})
|
78
76
|
|
79
|
-
expect(
|
80
|
-
CommandZ.
|
77
|
+
expect(onStatusChangeCallback.calls.length).toBe(7)
|
78
|
+
CommandZ.onStatusChange(null)
|
79
|
+
|
80
|
+
describe 'storage', ->
|
81
|
+
data = null
|
82
|
+
|
83
|
+
beforeEach ->
|
84
|
+
CommandZ.reset()
|
85
|
+
[1..3].forEach (i) -> CommandZ.store({ width: i * 100, height: i * 100 })
|
86
|
+
|
87
|
+
it 'stores data', ->
|
88
|
+
expect(CommandZ.history.length).toBe(3)
|
89
|
+
expect(CommandZ.index).toBe(2)
|
90
|
+
|
91
|
+
it 'undo', ->
|
92
|
+
CommandZ.onStorageChange (storageData) -> data = storageData
|
93
|
+
CommandZ.undo()
|
94
|
+
|
95
|
+
expect(data).toEqual({ width: 200, height: 200 })
|
96
|
+
|
97
|
+
it 'redo', ->
|
98
|
+
CommandZ.undo()
|
99
|
+
CommandZ.onStorageChange (storageData) -> data = storageData
|
100
|
+
CommandZ.redo()
|
101
|
+
|
102
|
+
expect(data).toEqual({ width: 300, height: 300 })
|
103
|
+
|
104
|
+
it 'undo and redo many times', ->
|
105
|
+
spyOn(CommandZ, 'sendData')
|
106
|
+
|
107
|
+
CommandZ.undo(2)
|
108
|
+
CommandZ.redo(2)
|
109
|
+
expect(CommandZ.sendData.calls.length).toBe(4)
|
110
|
+
|
111
|
+
CommandZ.redo(100)
|
112
|
+
expect(CommandZ.sendData.calls.length).toBe(4)
|
113
|
+
|
114
|
+
it 'has a threshold', ->
|
115
|
+
spyOn(CommandZ, 'sendData')
|
116
|
+
|
117
|
+
CommandZ.setThreshold(500)
|
118
|
+
CommandZ.undo(100)
|
119
|
+
|
120
|
+
waits(450)
|
121
|
+
runs -> expect(CommandZ.sendData.calls.length).toBe(0)
|
122
|
+
|
123
|
+
waits(100)
|
124
|
+
runs -> expect(CommandZ.sendData.calls.length).toBe(1)
|
81
125
|
|
82
126
|
describe 'integration', ->
|
83
127
|
$container = null
|
84
128
|
|
85
129
|
beforeEach ->
|
86
|
-
CommandZ.
|
87
|
-
loadFixtures('spec_container.html')
|
130
|
+
CommandZ.reset()
|
88
131
|
|
132
|
+
loadFixtures('spec_container.html')
|
89
133
|
$container = $('#spec-container')
|
134
|
+
|
90
135
|
[0..4].forEach ->
|
91
136
|
$test = $('<div class="foo"></div>')
|
92
137
|
CommandZ.execute
|
@@ -132,3 +177,28 @@ describe 'CommandZ', ->
|
|
132
177
|
|
133
178
|
CommandZ.undo()
|
134
179
|
expect($container.html()).toBe('')
|
180
|
+
|
181
|
+
it 'restores states with stored data', ->
|
182
|
+
img = new Image
|
183
|
+
$container.html(img)
|
184
|
+
|
185
|
+
CommandZ.onStorageChange (data) ->
|
186
|
+
img.width = data.width
|
187
|
+
img.height = data.height
|
188
|
+
|
189
|
+
img.width = 100
|
190
|
+
img.height = 100
|
191
|
+
|
192
|
+
[1..4].forEach (i) -> CommandZ.store({ width: i * 100, height: i * 100 })
|
193
|
+
|
194
|
+
CommandZ.undo(2)
|
195
|
+
expect(img.width).toBe(200)
|
196
|
+
|
197
|
+
CommandZ.redo()
|
198
|
+
expect(img.width).toBe(300)
|
199
|
+
|
200
|
+
CommandZ.redo(100)
|
201
|
+
expect(img.width).toBe(400)
|
202
|
+
|
203
|
+
CommandZ.undo(100)
|
204
|
+
expect(img.width).toBe(100)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: commandz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Etienne Lemay
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|