unpoly-rails 0.30.0 → 0.30.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f8c90c3524cc53bceb112f2a7fe498d4a7eda786
4
- data.tar.gz: 979eaa1084743303e20c6ecd7f430e64751797bd
3
+ metadata.gz: 1e53ab2c1cbdfe09b80e31d76371d5382ad40f70
4
+ data.tar.gz: 7ba79eb21d2494bf69b3bc222a4b7e89778671a1
5
5
  SHA512:
6
- metadata.gz: 42c4bd9af359d17e34a0741e0a06a1074ae90ee87143cd150679f47b2035a18f2b613e12df74c4ba313b5eddf5abdf84710f5c324bd030a80ca9e33802f71caa
7
- data.tar.gz: 74539855e8eadf62b68ca6a88e09b2ef2b6f5227eedb616c0395579e1d48eda87e4b1ca998fe9bdf5c13b48114caee59db83377c96892d8cfd6578d65b445b43
6
+ metadata.gz: 5789b11f34c69787dbf6fdd9fe9ed03d6c25c5c76fbf32b7028fcba36a6ecad14072c10d1cf5b4945d7edd104d11e581a302f6ca45b1c15baf4b5aa868c90691
7
+ data.tar.gz: 3d07d31ce7a01814badad2a7e16fbe4bbf283dc574a6b27818ea9a2ba5a6cff9b9fdcf6a9acfd19b6d505d12f8c84486ea12b7322fae39fa7000cb9af3492c1d
data/CHANGELOG.md CHANGED
@@ -14,6 +14,16 @@ Unreleased
14
14
  ### Breaking changes
15
15
 
16
16
 
17
+ 0.30.1
18
+ ------
19
+
20
+ ### Compatible changes
21
+
22
+ - Fix [`up.observe`](/up.observe) not honoring `{ delay }` option
23
+ - Fix [`[up-observe]`](/up-observe) not honoring `[up-delay]` modifier
24
+ - Fix many issues with concurrency and slow server responses for [`up.observe`](/up.observe) and [`[up-observe]`](/up-observe)
25
+
26
+
17
27
 
18
28
  0.30.0
19
29
  ------
@@ -249,52 +249,35 @@ up.form = (($) ->
249
249
  delay = u.option($fields.attr('up-delay'), options.delay, config.observeDelay)
250
250
  delay = parseInt(delay)
251
251
 
252
+ console.debug("Observing with delay %o", delay)
253
+
252
254
  destructors = u.map $fields, (field) ->
253
- observeField($(field), options, callback)
255
+ observeField($(field), delay, callback)
254
256
 
255
257
  u.sequence(destructors...)
256
258
 
257
259
  observeField = ($field, delay, callback) ->
258
- knownValue = null
259
- callbackTimer = null
260
- callbackPromise = u.resolvedPromise()
261
-
262
- # This holds the next callback function, curried with `value` and `$field`.
263
- # Since we're waiting for callback promises to resolve before running
264
- # another callback, this might be overwritten while we're waiting for a
265
- # previous callback to finish.
266
- nextCallback = null
267
-
268
- runNextCallback = ->
269
- if nextCallback
270
- returnValue = nextCallback()
271
- nextCallback = null
272
- returnValue
260
+ processedValue = u.submittedValue($field)
261
+ timer = undefined
262
+ lastCallbackDone = u.resolvedPromise()
263
+
264
+ runCallback = (value) ->
265
+ processedValue = value
266
+ callbackReturnValue = callback.apply($field.get(0), [value, $field])
267
+ if u.isPromise(callbackReturnValue)
268
+ lastCallbackDone = callbackReturnValue
269
+ else
270
+ lastCallbackDone = callbackReturnValue
273
271
 
274
272
  check = ->
275
273
  value = u.submittedValue($field)
276
274
  # don't run the callback for the check during initialization
277
- skipCallback = u.isNull(knownValue)
278
- if knownValue != value
279
- knownValue = value
280
- unless skipCallback
281
- clearTimer()
282
- nextCallback = -> callback.apply($field.get(0), [value, $field])
283
- runAndChain = ->
284
- # Only run the callback once the previous callback's
285
- # promise resolves.
286
- callbackPromise.then ->
287
- returnValue = runNextCallback()
288
- # If the callback returns a promise, we will remember it
289
- # and chain additional callback invocations to it.
290
- if u.isPromise(returnValue)
291
- callbackPromise = returnValue
292
- else
293
- callbackPromise = u.resolvedPromise()
294
- u.setTimer(delay, runAndChain)
295
-
296
- clearTimer = ->
297
- clearTimeout(callbackTimer)
275
+ if processedValue != value
276
+ nextCallback = -> runCallback(value)
277
+ timer?.cancel()
278
+ timer = u.promiseTimer(delay)
279
+ # We wait until both the delay has passed and a previous callback is done executing
280
+ $.when(timer, lastCallbackDone).then(nextCallback)
298
281
 
299
282
  # Although (depending on the browser) we only need/receive either input or change,
300
283
  # we always bind to both events in case another script manually triggers it.
@@ -307,12 +290,10 @@ up.form = (($) ->
307
290
 
308
291
  $field.on(changeEvents, check)
309
292
 
310
- check()
311
-
312
293
  # return destructor
313
294
  return ->
314
295
  $field.off(changeEvents, check)
315
- clearTimer()
296
+ timer?.cancel()
316
297
 
317
298
  ###*
318
299
  [Observes](/up.observe) a field or form and submits the form when a value changes.
@@ -860,7 +841,7 @@ up.form = (($) ->
860
841
  but not if the checkbox was changed:
861
842
 
862
843
  <form method="GET" action="/search">
863
- <input type="search" name="query" autosubmit>
844
+ <input type="search" name="query" up-autosubmit>
864
845
  <input type="checkbox"> Include archive
865
846
  </form>
866
847
 
@@ -778,6 +778,7 @@ up.util = (($) ->
778
778
  setTimeout(callback, millis)
779
779
  else
780
780
  callback()
781
+ undefined
781
782
 
782
783
 
783
784
  ###*
@@ -1777,14 +1778,21 @@ up.util = (($) ->
1777
1778
  The proxy's `.promise` attribute is available even before the function is called
1778
1779
  and will resolve when the inner function's returned promise resolves.
1779
1780
 
1781
+ If the inner function does not return a promise, the proxy's `.promise` attribute
1782
+ will resolve as soon as the inner function returns.
1783
+
1780
1784
  @function up.util.previewable
1781
1785
  @internal
1782
1786
  ###
1783
1787
  previewable = (fun) ->
1784
1788
  deferred = $.Deferred()
1785
1789
  preview = (args...) ->
1786
- fun(args...).then ->
1787
- deferred.resolve()
1790
+ funValue = fun(args...)
1791
+ if isPromise(funValue)
1792
+ funValue.then -> deferred.resolve(funValue)
1793
+ else
1794
+ deferred.resolve(funValue)
1795
+ funValue
1788
1796
  preview.promise = deferred.promise()
1789
1797
  preview
1790
1798
 
@@ -1844,6 +1852,27 @@ up.util = (($) ->
1844
1852
  ->
1845
1853
  map functions, (f) -> f()
1846
1854
 
1855
+ # ###*
1856
+ # @function up.util.race
1857
+ # @internal
1858
+ # ###
1859
+ # race = (promises...) ->
1860
+ # raceDone = $.Deferred()
1861
+ # each promises, (promise) ->
1862
+ # promise.then -> raceDone.resolve()
1863
+ # raceDone.promise()
1864
+
1865
+ ###*
1866
+ @function up.util.promiseTimer
1867
+ @internal
1868
+ ###
1869
+ promiseTimer = (ms) ->
1870
+ deferred = $.Deferred()
1871
+ timeout = setTimer ms, ->
1872
+ deferred.resolve()
1873
+ deferred.cancel = -> clearTimeout(timeout)
1874
+ deferred
1875
+
1847
1876
  isDetached: isDetached
1848
1877
  requestDataAsArray: requestDataAsArray
1849
1878
  requestDataAsQuery: requestDataAsQuery
@@ -1952,6 +1981,8 @@ up.util = (($) ->
1952
1981
  DivertibleChain: DivertibleChain
1953
1982
  submittedValue: submittedValue
1954
1983
  sequence: sequence
1984
+ promiseTimer: promiseTimer
1985
+ previewable: previewable
1955
1986
 
1956
1987
  )($)
1957
1988
 
@@ -4,6 +4,6 @@ module Unpoly
4
4
  # The current version of the unpoly-rails gem.
5
5
  # This version number is also used for releases of the Unpoly
6
6
  # frontend code.
7
- VERSION = '0.30.0'
7
+ VERSION = '0.30.1'
8
8
  end
9
9
  end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- unpoly-rails (0.28.1)
4
+ unpoly-rails (0.30.0)
5
5
  rails (>= 3)
6
6
 
7
7
  GEM
@@ -82,8 +82,8 @@ GEM
82
82
  hpricot (~> 0.8.6)
83
83
  ruby_parser (~> 3.1.1)
84
84
  i18n (0.7.0)
85
- jasmine-core (2.4.1)
86
- jasmine-rails (0.12.2)
85
+ jasmine-core (2.5.2)
86
+ jasmine-rails (0.14.1)
87
87
  jasmine-core (>= 1.3, < 3.0)
88
88
  phantomjs (>= 1.9)
89
89
  railties (>= 3.2.0)
@@ -99,12 +99,14 @@ GEM
99
99
  mail (2.6.3)
100
100
  mime-types (>= 1.16, < 3)
101
101
  mime-types (2.99)
102
- mini_portile2 (2.0.0)
103
- minitest (5.8.4)
104
- multi_json (1.11.2)
105
- nokogiri (1.6.7.2)
106
- mini_portile2 (~> 2.0.0.rc2)
107
- phantomjs (1.9.8.0)
102
+ mini_portile2 (2.1.0)
103
+ minitest (5.9.1)
104
+ multi_json (1.12.1)
105
+ nokogiri (1.6.8)
106
+ mini_portile2 (~> 2.1.0)
107
+ pkg-config (~> 1.1.7)
108
+ phantomjs (2.1.1.0)
109
+ pkg-config (1.1.7)
108
110
  rack (1.6.4)
109
111
  rack-test (0.6.3)
110
112
  rack (>= 1.0)
@@ -132,7 +134,7 @@ GEM
132
134
  activesupport (= 4.2.0)
133
135
  rake (>= 0.8.7)
134
136
  thor (>= 0.18.1, < 2.0)
135
- rake (11.1.2)
137
+ rake (11.3.0)
136
138
  ref (1.0.5)
137
139
  rspec-core (3.4.1)
138
140
  rspec-support (~> 3.4.0)
@@ -1,3 +1,2 @@
1
1
  beforeAll (done) ->
2
2
  $(done)
3
-
@@ -3,7 +3,7 @@ describe 'up.form', ->
3
3
  u = up.util
4
4
 
5
5
  describe 'Javascript functions', ->
6
-
6
+
7
7
  describe 'up.observe', ->
8
8
 
9
9
  beforeEach ->
@@ -23,43 +23,100 @@ describe 'up.form', ->
23
23
 
24
24
  u.each changeEvents, (eventName) ->
25
25
 
26
- it "runs the callback when the input receives a '#{eventName}' event and the value changed", (done) ->
27
- $input = affix('input[value="old-value"]')
28
- callback = jasmine.createSpy('change callback')
29
- up.observe($input, callback)
30
- $input.val('new-value')
31
- u.times 2, -> $input.trigger(eventName)
32
- u.nextFrame ->
33
- expect(callback).toHaveBeenCalledWith('new-value', $input)
34
- expect(callback.calls.count()).toEqual(1)
35
- done()
26
+ describe "when the input receives a #{eventName} event", ->
36
27
 
37
- it "does not run the callback when the input receives a '#{eventName}' event, but the value didn't change", (done) ->
38
- $input = affix('input[value="old-value"]')
39
- callback = jasmine.createSpy('change callback')
40
- up.observe($input, callback)
41
- $input.trigger(eventName)
42
- u.nextFrame ->
43
- expect(callback).not.toHaveBeenCalled()
44
- done()
28
+ it "runs the callback if the value changed", (done) ->
29
+ $input = affix('input[value="old-value"]')
30
+ callback = jasmine.createSpy('change callback')
31
+ up.observe($input, callback)
32
+ $input.val('new-value')
33
+ u.times 2, -> $input.trigger(eventName)
34
+ u.nextFrame ->
35
+ expect(callback).toHaveBeenCalledWith('new-value', $input)
36
+ expect(callback.calls.count()).toEqual(1)
37
+ done()
45
38
 
46
- it "runs a callback in the same frame if the delay is 0 and it receives a '#{eventName}' event", ->
47
- $input = affix('input[value="old-value"]')
48
- callback = jasmine.createSpy('change callback')
49
- up.observe($input, { delay: 0 }, callback)
50
- $input.val('new-value')
51
- $input.trigger(eventName)
52
- expect(callback.calls.count()).toEqual(1)
39
+ it "does not run the callback if the value didn't change", (done) ->
40
+ $input = affix('input[value="old-value"]')
41
+ callback = jasmine.createSpy('change callback')
42
+ up.observe($input, callback)
43
+ $input.trigger(eventName)
44
+ u.nextFrame ->
45
+ expect(callback).not.toHaveBeenCalled()
46
+ done()
53
47
 
54
- it "runs multiple callbacks in the same frame if the delay is 0 and it receives a '#{eventName}' event", ->
55
- $input = affix('input[value="old-value"]')
56
- callback = jasmine.createSpy('change callback')
57
- up.observe($input, { delay: 0 }, callback)
58
- $input.val('new-value')
59
- $input.trigger(eventName)
60
- $input.val('yet-another-value')
61
- $input.trigger(eventName)
62
- expect(callback.calls.count()).toEqual(2)
48
+ it 'debounces the callback when the { delay } option is given', (done) ->
49
+ $input = affix('input[value="old-value"]')
50
+ callback = jasmine.createSpy('change callback')
51
+ up.observe($input, { delay: 100 }, callback)
52
+ $input.val('new-value-1')
53
+ $input.trigger(eventName)
54
+ u.setTimer 50, ->
55
+ # 50 ms after change 1: We're still waiting for the 100ms delay to expire
56
+ expect(callback.calls.count()).toEqual(0)
57
+ u.setTimer 100, ->
58
+ # 150 ms after change 1: The 100ms delay has expired
59
+ expect(callback.calls.count()).toEqual(1)
60
+ expect(callback.calls.mostRecent().args[0]).toEqual('new-value-1')
61
+ $input.val('new-value-2')
62
+ $input.trigger(eventName)
63
+ u.setTimer 40, ->
64
+ # 40 ms after change 2: We change again, resetting the delay
65
+ expect(callback.calls.count()).toEqual(1)
66
+ $input.val('new-value-3')
67
+ $input.trigger(eventName)
68
+ u.setTimer 85, ->
69
+ # 125 ms after change 2, which was superseded by change 3
70
+ # 85 ms after change 3
71
+ expect(callback.calls.count()).toEqual(1)
72
+ u.setTimer 65, ->
73
+ # 190 ms after change 2, which was superseded by change 3
74
+ # 150 ms after change 3
75
+ expect(callback.calls.count()).toEqual(2)
76
+ expect(callback.calls.mostRecent().args[0]).toEqual('new-value-3')
77
+ done()
78
+
79
+ it 'delays a callback if a previous async callback is taking long to execute', (done) ->
80
+ $input = affix('input[value="old-value"]')
81
+ callbackCount = 0
82
+ callback = ->
83
+ callbackCount += 1
84
+ u.promiseTimer(100)
85
+ up.observe($input, { delay: 1 }, callback)
86
+ $input.val('new-value-1')
87
+ $input.trigger(eventName)
88
+ u.setTimer 30, ->
89
+ # Callback has been called and takes 100 ms to complete
90
+ expect(callbackCount).toEqual(1)
91
+ $input.val('new-value-2')
92
+ $input.trigger(eventName)
93
+ u.setTimer 30, ->
94
+ # Second callback is triggerd, but waits for first callback to complete
95
+ expect(callbackCount).toEqual(1)
96
+ u.setTimer 100, ->
97
+ expect(callbackCount).toEqual(2)
98
+ done()
99
+
100
+ it 'does not run multiple callbacks if a long-running callback has been blocking multiple subsequent callbacks'
101
+
102
+ it "runs a callback in the same frame if the delay is 0", ->
103
+ console.debug('*** next example')
104
+ $input = affix('input[value="old-value"]')
105
+ callback = jasmine.createSpy('change callback')
106
+ up.observe($input, { delay: 0 }, callback)
107
+ $input.val('new-value')
108
+ $input.trigger(eventName)
109
+ expect(callback.calls.count()).toEqual(1)
110
+
111
+ it "runs multiple callbacks in the same frame if the delay is 0", ->
112
+ $input = affix('input[value="old-value"]')
113
+ callback = jasmine.createSpy('change callback')
114
+ up.observe($input, { delay: 0 }, callback)
115
+ $input.val('new-value')
116
+ $input.trigger(eventName)
117
+ $input.val('yet-another-value')
118
+ $input.trigger(eventName)
119
+ expect(callback.calls.count()).toEqual(2)
63
120
 
64
121
  describe 'when the first argument is a checkbox', ->
65
122
 
@@ -163,42 +220,44 @@ describe 'up.form', ->
163
220
 
164
221
  u.each changeEvents, (eventName) ->
165
222
 
166
- it "runs the callback when any of the form's inputs receives a '#{eventName}' event and the value changed", (done) ->
167
- $form = affix('form')
168
- $input = $form.affix('input[value="old-value"]')
169
- callback = jasmine.createSpy('change callback')
170
- up.observe($form, callback)
171
- $input.val('new-value')
172
- u.times 2, -> $input.trigger(eventName)
173
- u.nextFrame ->
174
- expect(callback).toHaveBeenCalledWith('new-value', $input)
175
- expect(callback.calls.count()).toEqual(1)
176
- done()
223
+ describe "when any of the form's inputs receives a #{eventName} event", ->
177
224
 
178
- it "does not run the callback when any of the form's inputs receives a '#{eventName}' event, but the value didn't change", (done) ->
179
- $form = affix('form')
180
- $input = $form.affix('input[value="old-value"]')
181
- callback = jasmine.createSpy('change callback')
182
- up.observe($form, callback)
183
- $input.trigger(eventName)
184
- u.nextFrame ->
185
- expect(callback).not.toHaveBeenCalled()
186
- done()
225
+ it "runs the callback if the value changed", (done) ->
226
+ $form = affix('form')
227
+ $input = $form.affix('input[value="old-value"]')
228
+ callback = jasmine.createSpy('change callback')
229
+ up.observe($form, callback)
230
+ $input.val('new-value')
231
+ u.times 2, -> $input.trigger(eventName)
232
+ u.nextFrame ->
233
+ expect(callback).toHaveBeenCalledWith('new-value', $input)
234
+ expect(callback.calls.count()).toEqual(1)
235
+ done()
187
236
 
188
- # it 'runs the callback only once when a radio button group changes its selection', ->
189
- # $form = affix('form')
190
- # $radio1 = $form.affix('input[type="radio"][name="group"][value="1"][checked="checked"]')
191
- # $radio2 = $form.affix('input[type="radio"][name="group"][value="2"]')
192
- # callback = jasmine.createSpy('change callback')
193
- # up.observe($form, callback)
194
- # $radio2.get(0).click()
195
- # u.nextFrame ->
196
- # expect(callback.calls.count()).toEqual(1)
237
+ it "does not run the callback if the value didn't change", (done) ->
238
+ $form = affix('form')
239
+ $input = $form.affix('input[value="old-value"]')
240
+ callback = jasmine.createSpy('change callback')
241
+ up.observe($form, callback)
242
+ $input.trigger(eventName)
243
+ u.nextFrame ->
244
+ expect(callback).not.toHaveBeenCalled()
245
+ done()
246
+
247
+ # it 'runs the callback only once when a radio button group changes its selection', ->
248
+ # $form = affix('form')
249
+ # $radio1 = $form.affix('input[type="radio"][name="group"][value="1"][checked="checked"]')
250
+ # $radio2 = $form.affix('input[type="radio"][name="group"][value="2"]')
251
+ # callback = jasmine.createSpy('change callback')
252
+ # up.observe($form, callback)
253
+ # $radio2.get(0).click()
254
+ # u.nextFrame ->
255
+ # expect(callback.calls.count()).toEqual(1)
197
256
 
198
257
  describe 'up.submit', ->
199
258
 
200
259
  describeCapability 'canPushState', ->
201
-
260
+
202
261
  beforeEach ->
203
262
  @$form = affix('form[action="/path/to"][method="put"][up-target=".response"]')
204
263
  @$form.append('<input name="field1" value="value1">')
@@ -232,11 +291,11 @@ describe 'up.form', ->
232
291
  responseText:
233
292
  """
234
293
  text-before
235
-
294
+
236
295
  <form>
237
296
  error-messages
238
297
  </form>
239
-
298
+
240
299
  text-after
241
300
  """
242
301
  expect(up.browser.url()).toEqual(@hrefBeforeExample)
@@ -300,12 +359,12 @@ describe 'up.form', ->
300
359
  expect(form.submit).toHaveBeenCalled()
301
360
 
302
361
  describeFallback 'canPushState', ->
303
-
362
+
304
363
  it 'falls back to a vanilla form submission', ->
305
364
  $form = affix('form[action="/path/to"][method="put"][up-target=".response"]')
306
365
  form = $form.get(0)
307
366
  spyOn(form, 'submit')
308
-
367
+
309
368
  up.submit($form)
310
369
  expect(form.submit).toHaveBeenCalled()
311
370
 
@@ -358,7 +417,10 @@ describe 'up.form', ->
358
417
 
359
418
  describe '[up-observe]', ->
360
419
 
361
- it 'runs the Javascript code in the attribute value when a change is observed in the field', ->
420
+ afterEach ->
421
+ window.observeCallbackSpy = undefined
422
+
423
+ it 'runs the Javascript code in the attribute value when a change is observed in the field', (done) ->
362
424
  $form = affix('form')
363
425
  window.observeCallbackSpy = jasmine.createSpy('observe callback')
364
426
  $field = $form.affix('input[val="old-value"][up-observe="window.observeCallbackSpy(value, $field.get(0))"]')
@@ -369,6 +431,20 @@ describe 'up.form', ->
369
431
  expect(window.observeCallbackSpy).toHaveBeenCalledWith('new-value', $field.get(0))
370
432
  done()
371
433
 
434
+ describe 'with [up-delay] modifier', ->
435
+
436
+ it 'debounces the callback', (done) ->
437
+ $form = affix('form')
438
+ window.observeCallbackSpy = jasmine.createSpy('observe callback')
439
+ $field = $form.affix('input[val="old-value"][up-observe="window.observeCallbackSpy()"][up-delay="50"]')
440
+ up.hello($form)
441
+ $field.val('new-value')
442
+ $field.trigger('change')
443
+ u.nextFrame ->
444
+ expect(window.observeCallbackSpy).not.toHaveBeenCalled()
445
+ u.setTimer 80, ->
446
+ expect(window.observeCallbackSpy).toHaveBeenCalled()
447
+ done()
372
448
 
373
449
  describe 'input[up-validate]', ->
374
450
 
@@ -1,7 +1,85 @@
1
1
  describe 'up.util', ->
2
-
2
+
3
+ u = up.util
4
+
3
5
  describe 'Javascript functions', ->
4
6
 
7
+ describe 'up.util.previewable', ->
8
+
9
+ it 'wraps a function into a proxy function with an additional .promise attribute', ->
10
+ fun = -> 'return value'
11
+ proxy = up.util.previewable(fun)
12
+ expect(u.isFunction(proxy)).toBe(true)
13
+ expect(u.isPromise(proxy.promise)).toBe(true)
14
+ expect(proxy()).toEqual('return value')
15
+
16
+ it "resolves the proxy's .promise when the inner function returns", (done) ->
17
+ fun = -> 'return value'
18
+ proxy = up.util.previewable(fun)
19
+ callback = jasmine.createSpy('promise callback')
20
+ proxy.promise.then(callback)
21
+ u.nextFrame ->
22
+ expect(callback).not.toHaveBeenCalled()
23
+ proxy()
24
+ u.nextFrame ->
25
+ expect(callback).toHaveBeenCalledWith('return value')
26
+ done()
27
+
28
+ it "delays resolution of the proxy's .promise if the inner function returns a promise", (done) ->
29
+ funDeferred = $.Deferred()
30
+ fun = -> funDeferred
31
+ proxy = up.util.previewable(fun)
32
+ callback = jasmine.createSpy('promise callback')
33
+ proxy.promise.then(callback)
34
+ proxy()
35
+ u.nextFrame ->
36
+ expect(callback).not.toHaveBeenCalled()
37
+ funDeferred.resolve()
38
+ u.nextFrame ->
39
+ expect(callback).toHaveBeenCalled()
40
+ done()
41
+
42
+ describe 'up.util.DivertibleChain', ->
43
+
44
+ it "instantiates a task queue whose (2..n)th tasks can be changed by calling '.asap'", (done) ->
45
+ chain = new up.util.DivertibleChain()
46
+
47
+ timer1Spy = jasmine.createSpy('timer1 has been called')
48
+ timer1 = ->
49
+ timer1Spy()
50
+ u.promiseTimer(50)
51
+
52
+ timer2Spy = jasmine.createSpy('timer2 has been called')
53
+ timer2 = ->
54
+ timer2Spy()
55
+ u.promiseTimer(50)
56
+
57
+ timer3Spy = jasmine.createSpy('timer3 has been called')
58
+ timer3 = ->
59
+ timer3Spy()
60
+ u.promiseTimer(50)
61
+
62
+ timer4Spy = jasmine.createSpy('timer4 has been called')
63
+ timer4 = ->
64
+ timer4Spy()
65
+ u.promiseTimer(50)
66
+
67
+ chain.asap(timer1)
68
+ u.nextFrame ->
69
+ expect(timer1Spy).toHaveBeenCalled()
70
+ chain.asap(timer2)
71
+ u.nextFrame ->
72
+ # timer2 is still waiting for timer1 to finish
73
+ expect(timer2Spy).not.toHaveBeenCalled()
74
+ # Override the (2..n)th tasks. This unschedules timer2.
75
+ chain.asap(timer3, timer4)
76
+ u.setTimer 80, ->
77
+ expect(timer2Spy).not.toHaveBeenCalled()
78
+ expect(timer3Spy).toHaveBeenCalled()
79
+ u.setTimer 70, ->
80
+ expect(timer4Spy).toHaveBeenCalled()
81
+ done()
82
+
5
83
  describe 'up.util.sequence', ->
6
84
 
7
85
  it 'combines the given functions into a single function', ->
@@ -144,10 +222,17 @@ describe 'up.util', ->
144
222
  jasmine.clock().tick(1500)
145
223
  expect(callback).toHaveBeenCalled()
146
224
 
147
- it 'calls the given function in the current execution frame if the delay is zero', ->
148
- callback = jasmine.createSpy()
149
- up.util.setTimer(0, callback)
150
- expect(callback).toHaveBeenCalled()
225
+ describe 'if the delay is zero', ->
226
+
227
+ it 'calls the given function in the current execution frame', ->
228
+ callback = jasmine.createSpy()
229
+ up.util.setTimer(0, callback)
230
+ expect(callback).toHaveBeenCalled()
231
+
232
+ it "returns undefined so the return value won't be mistaken with a Javascript timer ID", ->
233
+ callback = -> 'function return value'
234
+ timerReturnValue = up.util.setTimer(0, callback)
235
+ expect(timerReturnValue).toBeUndefined()
151
236
 
152
237
  # describe 'up.util.argNames', ->
153
238
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unpoly-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.0
4
+ version: 0.30.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henning Koch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-20 00:00:00.000000000 Z
11
+ date: 2016-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails