unpoly-rails 0.20.0 → 0.21.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.

Potentially problematic release.


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

@@ -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.20.0'
7
+ VERSION = '0.21.0'
8
8
  end
9
9
  end
@@ -32,12 +32,21 @@ describe 'up.flow', ->
32
32
  expect($('.after')).toHaveText('old-after')
33
33
  done()
34
34
 
35
- it 'sends an X-Up-Target HTTP headers along with the request', ->
35
+ it 'sends an X-Up-Target HTTP header along with the request', ->
36
36
  up.replace('.middle', '/path')
37
37
  request = @lastRequest()
38
- console.log(request.requestHeaders)
39
38
  expect(request.requestHeaders['X-Up-Target']).toEqual('.middle')
40
39
 
40
+ it 'returns a promise that will be resolved once the server response was received and the fragments were swapped', ->
41
+ resolution = jasmine.createSpy()
42
+ promise = up.replace('.middle', '/path')
43
+ promise.then(resolution)
44
+ expect(resolution).not.toHaveBeenCalled()
45
+ expect($('.middle')).toHaveText('old-middle')
46
+ @respond()
47
+ expect(resolution).toHaveBeenCalled()
48
+ expect($('.middle')).toHaveText('new-middle')
49
+
41
50
  describe 'with { data } option', ->
42
51
 
43
52
  it "uses the given params as a non-GET request's payload", ->
@@ -457,6 +466,78 @@ describe 'up.flow', ->
457
466
  expect($(elements.get(0)).text()).toEqual('text')
458
467
  expect($(elements.get(1)).text()).toEqual('')
459
468
 
469
+ describe 'with { transition } option', ->
470
+
471
+ it 'morphs between the old and new element', (done) ->
472
+ affix('.element').text('version 1')
473
+ up.extract('.element', '<div class="element">version 2</div>', transition: 'cross-fade', duration: 50)
474
+
475
+ $ghost1 = $('.element.up-ghost:contains("version 1")')
476
+ expect($ghost1).toHaveLength(1)
477
+ expect($ghost1.css('opacity')).toBeAround(1.0, 0.1)
478
+
479
+ $ghost2 = $('.element.up-ghost:contains("version 2")')
480
+ expect($ghost2).toHaveLength(1)
481
+ expect($ghost2.css('opacity')).toBeAround(0.0, 0.1)
482
+
483
+ @setTimer 40, ->
484
+ expect($ghost1.css('opacity')).toBeAround(0.0, 0.2)
485
+ expect($ghost2.css('opacity')).toBeAround(1.0, 0.2)
486
+ done()
487
+
488
+ it 'marks the old fragment and its ghost as .up-destroying during the transition', ->
489
+ affix('.element').text('version 1')
490
+ up.extract('.element', '<div class="element">version 2</div>', transition: 'cross-fade', duration: 200)
491
+
492
+ $version1 = $('.element:not(.up-ghost):contains("version 1")')
493
+ $version1Ghost = $('.element.up-ghost:contains("version 1")')
494
+ expect($version1).toHaveLength(1)
495
+ expect($version1Ghost).toHaveLength(1)
496
+ expect($version1).toHaveClass('up-destroying')
497
+ expect($version1Ghost).toHaveClass('up-destroying')
498
+
499
+ $version2 = $('.element:not(.up-ghost):contains("version 2")')
500
+ $version2Ghost = $('.element.up-ghost:contains("version 2")')
501
+ expect($version2).toHaveLength(1)
502
+ expect($version2Ghost).toHaveLength(1)
503
+ expect($version2).not.toHaveClass('up-destroying')
504
+ expect($version2Ghost).not.toHaveClass('up-destroying')
505
+
506
+ it 'cancels an existing transition by instantly jumping to the last frame', ->
507
+ affix('.element').text('version 1')
508
+ up.extract('.element', '<div class="element">version 2</div>', transition: 'cross-fade', duration: 200)
509
+
510
+ $ghost1 = $('.element.up-ghost:contains("version 1")')
511
+ expect($ghost1).toHaveLength(1)
512
+ expect($ghost1.css('opacity')).toBeAround(1.0, 0.1)
513
+
514
+ $ghost2 = $('.element.up-ghost:contains("version 2")')
515
+ expect($ghost2).toHaveLength(1)
516
+ expect($ghost2.css('opacity')).toBeAround(0.0, 0.1)
517
+
518
+ up.extract('.element', '<div class="element">version 3</div>', transition: 'cross-fade', duration: 200)
519
+
520
+ $ghost1 = $('.element.up-ghost:contains("version 1")')
521
+ expect($ghost1).toHaveLength(0)
522
+
523
+ $ghost2 = $('.element.up-ghost:contains("version 2")')
524
+ expect($ghost2).toHaveLength(1)
525
+ expect($ghost2.css('opacity')).toBeAround(1.0, 0.1)
526
+
527
+ $ghost3 = $('.element.up-ghost:contains("version 3")')
528
+ expect($ghost3).toHaveLength(1)
529
+ expect($ghost3.css('opacity')).toBeAround(0.0, 0.1)
530
+
531
+ it 'delays the resolution of the returned promise until the transition is over', (done) ->
532
+ affix('.element').text('version 1')
533
+ resolution = jasmine.createSpy()
534
+ promise = up.extract('.element', '<div class="element">version 2</div>', transition: 'cross-fade', duration: 30)
535
+ promise.then(resolution)
536
+ expect(resolution).not.toHaveBeenCalled()
537
+ @setTimer 50, ->
538
+ expect(resolution).toHaveBeenCalled()
539
+ done()
540
+
460
541
  describe 'handling of [up-keep] elements', ->
461
542
 
462
543
  squish = (string) ->
@@ -509,8 +590,6 @@ describe 'up.flow', ->
509
590
  up.extract '.keeper', "<div class='keeper' up-keep>new-inside</div>"
510
591
  expect($('.keeper')).toHaveText('old-inside')
511
592
 
512
- it "does not compile the kept element a second time"
513
-
514
593
  it "only emits an event up:fragment:kept, but not an event up:fragment:inserted", ->
515
594
  insertedListener = jasmine.createSpy('subscriber to up:fragment:inserted')
516
595
  up.on('up:fragment:inserted', insertedListener)
@@ -282,12 +282,12 @@ describe 'up.form', ->
282
282
  expect($labels[0]).not.toHaveText('Validation message')
283
283
  expect($labels[1]).toHaveText('Validation message')
284
284
 
285
- describe '[up-toggle]', ->
285
+ describe '[up-switch]', ->
286
286
 
287
287
  describe 'on a select', ->
288
288
 
289
289
  beforeEach ->
290
- @$select = affix('select[up-toggle=".target"]')
290
+ @$select = affix('select[up-switch=".target"]')
291
291
  @$blankOption = @$select.affix('option').text('<Please select something>').val('')
292
292
  @$fooOption = @$select.affix('option[value="foo"]').text('Foo')
293
293
  @$barOption = @$select.affix('option[value="bar"]').text('Bar')
@@ -331,7 +331,7 @@ describe 'up.form', ->
331
331
  describe 'on a checkbox', ->
332
332
 
333
333
  beforeEach ->
334
- @$checkbox = affix('input[type="checkbox"][value="1"][up-toggle=".target"]')
334
+ @$checkbox = affix('input[type="checkbox"][value="1"][up-switch=".target"]')
335
335
 
336
336
  it "shows the target element iff its up-show-for attribute is :checked and the checkbox is checked", ->
337
337
  $target = affix('.target[up-show-for=":checked"]')
@@ -372,10 +372,10 @@ describe 'up.form', ->
372
372
 
373
373
  beforeEach ->
374
374
  @$buttons = affix('.radio-buttons')
375
- @$blankButton = @$buttons.affix('input[type="radio"][name="group"][up-toggle=".target"]').val('')
376
- @$fooButton = @$buttons.affix('input[type="radio"][name="group"][up-toggle=".target"]').val('foo')
377
- @$barButton = @$buttons.affix('input[type="radio"][name="group"][up-toggle=".target"]').val('bar')
378
- @$bazkButton = @$buttons.affix('input[type="radio"][name="group"][up-toggle=".target"]').val('baz')
375
+ @$blankButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('')
376
+ @$fooButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('foo')
377
+ @$barButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('bar')
378
+ @$bazkButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('baz')
379
379
 
380
380
  it "shows the target element iff its up-show-for attribute contains the selected button value", ->
381
381
  $target = affix('.target[up-show-for="something bar other"]')
@@ -433,7 +433,7 @@ describe 'up.form', ->
433
433
  describe 'on a text input', ->
434
434
 
435
435
  beforeEach ->
436
- @$textInput = affix('input[type="text"][up-toggle=".target"]')
436
+ @$textInput = affix('input[type="text"][up-switch=".target"]')
437
437
 
438
438
  it "shows the target element iff its up-show-for attribute contains the input value", ->
439
439
  $target = affix('.target[up-show-for="something bar other"]')
@@ -92,6 +92,53 @@ describe 'up.syntax', ->
92
92
  expect($baz.attr('up-keep')).toBeMissing()
93
93
  expect($bam.attr('up-keep')).toEqual('.partner')
94
94
 
95
+ describe 'with { priority } option', ->
96
+
97
+ it 'runs compilers with higher priority first', ->
98
+ traces = []
99
+ up.compiler '.element', { priority: 1 }, -> traces.push('foo')
100
+ up.compiler '.element', { priority: 2 }, -> traces.push('bar')
101
+ up.compiler '.element', { priority: 0 }, -> traces.push('baz')
102
+ up.compiler '.element', { priority: 3 }, -> traces.push('bam')
103
+ up.compiler '.element', { priority: -1 }, -> traces.push('qux')
104
+ up.hello(affix('.element'))
105
+ expect(traces).toEqual ['qux', 'baz', 'foo', 'bar', 'bam']
106
+
107
+ it 'considers priority-less compilers to be priority zero', ->
108
+ traces = []
109
+ up.compiler '.element', { priority: 1 }, -> traces.push('foo')
110
+ up.compiler '.element', -> traces.push('bar')
111
+ up.compiler '.element', { priority: -1 }, -> traces.push('baz')
112
+ up.hello(affix('.element'))
113
+ expect(traces).toEqual ['baz', 'bar', 'foo']
114
+
115
+ it 'runs two compilers with the same priority in the order in which they were registered', ->
116
+ traces = []
117
+ up.compiler '.element', { priority: 1 }, -> traces.push('foo')
118
+ up.compiler '.element', { priority: 1 }, -> traces.push('bar')
119
+ up.hello(affix('.element'))
120
+ expect(traces).toEqual ['foo', 'bar']
121
+
122
+ describe 'up.macro', ->
123
+
124
+ it 'registers compilers that are run before other compilers', ->
125
+ traces = []
126
+ up.compiler '.element', { priority: 10 }, -> traces.push('foo')
127
+ up.compiler '.element', { priority: -1000 }, -> traces.push('bar')
128
+ up.macro '.element', -> traces.push('baz')
129
+ up.hello(affix('.element'))
130
+ expect(traces).toEqual ['baz', 'bar' , 'foo']
131
+
132
+ it 'allows to macros to have priorities of their own', ->
133
+ traces = []
134
+ up.macro '.element', { priority: 1 }, -> traces.push('foo')
135
+ up.macro '.element', { priority: 2 }, -> traces.push('bar')
136
+ up.macro '.element', { priority: 0 }, -> traces.push('baz')
137
+ up.macro '.element', { priority: 3 }, -> traces.push('bam')
138
+ up.macro '.element', { priority: -1 }, -> traces.push('qux')
139
+ up.hello(affix('.element'))
140
+ expect(traces).toEqual ['qux', 'baz', 'foo', 'bar', 'bam']
141
+
95
142
  describe 'up.hello', ->
96
143
 
97
144
  it 'should have tests'
@@ -245,6 +245,82 @@ describe 'up.util', ->
245
245
  string = up.util.requestDataAsQuery({ 'my+key': 'my+value' })
246
246
  expect(string).toEqual('my%2Bkey=my%2Bvalue')
247
247
 
248
+ describe 'up.util.resolvableWhen', ->
249
+
250
+ it 'returns a promise that is resolved when all the given deferreds are resolved', ->
251
+ one = jasmine.createSpy()
252
+ two = jasmine.createSpy()
253
+ both = jasmine.createSpy()
254
+ oneDeferred = $.Deferred()
255
+ oneDeferred.then(one)
256
+ twoDeferred = $.Deferred()
257
+ twoDeferred.then(two)
258
+
259
+ bothDeferred = up.util.resolvableWhen(oneDeferred, twoDeferred)
260
+ bothDeferred.then(both)
261
+
262
+ expect(one).not.toHaveBeenCalled()
263
+ expect(two).not.toHaveBeenCalled()
264
+ expect(both).not.toHaveBeenCalled()
265
+
266
+ oneDeferred.resolve()
267
+ expect(one).toHaveBeenCalled()
268
+ expect(two).not.toHaveBeenCalled()
269
+ expect(both).not.toHaveBeenCalled()
270
+
271
+ twoDeferred.resolve()
272
+ expect(one).toHaveBeenCalled()
273
+ expect(two).toHaveBeenCalled()
274
+ expect(both).toHaveBeenCalled()
275
+
276
+ it 'returns a promise with a .resolve method that resolves the given deferreds', ->
277
+ one = jasmine.createSpy()
278
+ two = jasmine.createSpy()
279
+ both = jasmine.createSpy()
280
+ oneDeferred = $.Deferred()
281
+ oneDeferred.then(one)
282
+ twoDeferred = $.Deferred()
283
+ twoDeferred.then(two)
284
+
285
+ bothDeferred = up.util.resolvableWhen(oneDeferred, twoDeferred)
286
+ bothDeferred.then(both)
287
+
288
+ expect(one).not.toHaveBeenCalled()
289
+ expect(two).not.toHaveBeenCalled()
290
+ expect(both).not.toHaveBeenCalled()
291
+
292
+ bothDeferred.resolve()
293
+ expect(one).toHaveBeenCalled()
294
+ expect(two).toHaveBeenCalled()
295
+ expect(both).toHaveBeenCalled()
296
+
297
+ it 'does not resolve the given deferreds more than once', ->
298
+ oneDeferred = $.Deferred()
299
+ spyOn(oneDeferred, 'resolve')
300
+ bothDeferred = up.util.resolvableWhen(oneDeferred)
301
+
302
+ bothDeferred.resolve()
303
+ bothDeferred.resolve()
304
+
305
+ expect(oneDeferred.resolve.calls.count()).toEqual(1)
306
+
307
+ describe 'bugfix against troublesome jQuery optimization if only one deferred is given', ->
308
+
309
+ it 'does not simply return the given deferred', ->
310
+ oneDeferred = $.Deferred()
311
+ whenDeferred = up.util.resolvableWhen(oneDeferred)
312
+ # This is what $.when returns if only passed a single argument
313
+ expect(whenDeferred).not.toBe(oneDeferred.promise())
314
+ # Cover eventual implementations
315
+ expect(whenDeferred).not.toBe(oneDeferred)
316
+ expect(whenDeferred.promise()).not.toBe(oneDeferred.promise())
317
+ expect(whenDeferred.promise()).not.toBe(oneDeferred)
318
+
319
+ it 'does not create an infinite loop if the given deferred is nested twice and the first nesting is resolved', ->
320
+ oneDeferred = $.Deferred()
321
+ firstNesting = up.util.resolvableWhen(oneDeferred)
322
+ secondNesting = up.util.resolvableWhen(firstNesting)
323
+ expect(-> firstNesting.resolve()).not.toThrowError()
248
324
 
249
325
  describe 'up.util.requestDataAsArray', ->
250
326
 
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.20.0
4
+ version: 0.21.0
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-02-26 00:00:00.000000000 Z
11
+ date: 2016-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails