unpoly-rails 0.36.2 → 0.37.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.

Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +1 -1
  4. data/dist/unpoly.js +137 -73
  5. data/dist/unpoly.min.js +3 -3
  6. data/lib/assets/javascripts/unpoly/bus.coffee +2 -2
  7. data/lib/assets/javascripts/unpoly/dom/extract_plan.coffee +4 -2
  8. data/lib/assets/javascripts/unpoly/dom.coffee +26 -12
  9. data/lib/assets/javascripts/unpoly/form.coffee +19 -1
  10. data/lib/assets/javascripts/unpoly/layout.coffee +1 -1
  11. data/lib/assets/javascripts/unpoly/link.coffee +9 -2
  12. data/lib/assets/javascripts/unpoly/modal.coffee +1 -0
  13. data/lib/assets/javascripts/unpoly/popup.coffee +1 -0
  14. data/lib/assets/javascripts/unpoly/syntax.coffee +48 -29
  15. data/lib/assets/javascripts/unpoly/util.coffee +12 -5
  16. data/lib/unpoly/rails/version.rb +1 -1
  17. data/package.json +1 -1
  18. data/spec_app/Gemfile.lock +1 -1
  19. data/spec_app/app/assets/javascripts/integration_test.coffee +4 -0
  20. data/spec_app/app/controllers/replace_test_controller.rb +5 -0
  21. data/spec_app/app/views/pages/start.erb +4 -0
  22. data/spec_app/app/views/replace_test/_nav.erb +6 -0
  23. data/spec_app/app/views/replace_test/page1.erb +14 -0
  24. data/spec_app/app/views/replace_test/page2.erb +14 -0
  25. data/spec_app/config/routes.rb +1 -0
  26. data/spec_app/spec/javascripts/helpers/reset_path.js.coffee +1 -2
  27. data/spec_app/spec/javascripts/up/dom_spec.js.coffee +69 -1
  28. data/spec_app/spec/javascripts/up/feedback_spec.js.coffee +5 -3
  29. data/spec_app/spec/javascripts/up/history_spec.js.coffee +174 -153
  30. data/spec_app/spec/javascripts/up/link_spec.js.coffee +77 -19
  31. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +1 -1
  32. data/spec_app/spec/javascripts/up/util_spec.js.coffee +34 -0
  33. metadata +6 -2
@@ -10,211 +10,243 @@ describe 'up.history', ->
10
10
 
11
11
  describe 'up.history.url', ->
12
12
 
13
- describeCapability 'canPushState', ->
14
-
15
- it 'does not strip a trailing slash from the current URL', ->
16
- history.replaceState?({}, 'title', '/host/path/')
17
- expect(up.history.url()).toEqualUrl('/host/path/')
13
+ it 'does not strip a trailing slash from the current URL', ->
14
+ history.replaceState?({}, 'title', '/host/path/')
15
+ expect(up.history.url()).toEqualUrl('/host/path/')
18
16
 
19
17
  describe 'up.history.isUrl', ->
20
18
 
21
- describeCapability 'canPushState', ->
22
-
23
- it 'returns true if the given path is the current URL', ->
24
- history.replaceState?({}, 'title', '/host/path/')
25
- expect(up.history.isUrl('/host/path/')).toBe(true)
19
+ it 'returns true if the given path is the current URL', ->
20
+ history.replaceState?({}, 'title', '/host/path/')
21
+ expect(up.history.isUrl('/host/path/')).toBe(true)
26
22
 
27
- it 'returns false if the given path is not the current URL', ->
28
- history.replaceState?({}, 'title', '/host/path/')
29
- expect(up.history.isUrl('/host/other-path/')).toBe(false)
23
+ it 'returns false if the given path is not the current URL', ->
24
+ history.replaceState?({}, 'title', '/host/path/')
25
+ expect(up.history.isUrl('/host/other-path/')).toBe(false)
30
26
 
31
- it 'returns true if the given full URL is the current URL', ->
32
- history.replaceState?({}, 'title', '/host/path/')
33
- expect(up.history.isUrl("http://#{location.host}/host/path/")).toBe(true)
27
+ it 'returns true if the given full URL is the current URL', ->
28
+ history.replaceState?({}, 'title', '/host/path/')
29
+ expect(up.history.isUrl("http://#{location.host}/host/path/")).toBe(true)
34
30
 
35
- it 'returns true if the given path is the current URL, but without a trailing slash', ->
36
- history.replaceState?({}, 'title', '/host/path/')
37
- expect(up.history.isUrl('/host/path')).toBe(true)
31
+ it 'returns true if the given path is the current URL, but without a trailing slash', ->
32
+ history.replaceState?({}, 'title', '/host/path/')
33
+ expect(up.history.isUrl('/host/path')).toBe(true)
38
34
 
39
- it 'returns true if the given path is the current URL, but with a trailing slash', ->
40
- history.replaceState?({}, 'title', '/host/path')
41
- expect(up.history.isUrl('/host/path/')).toBe(true)
35
+ it 'returns true if the given path is the current URL, but with a trailing slash', ->
36
+ history.replaceState?({}, 'title', '/host/path')
37
+ expect(up.history.isUrl('/host/path/')).toBe(true)
42
38
 
43
39
  describe 'unobtrusive behavior', ->
44
40
 
45
- describe '[up-back]', ->
41
+ describe 'back button', ->
46
42
 
47
- describeCapability 'canPushState', ->
43
+ it 'calls destructor functions when destroying compiled elements (bugfix)', (done) ->
44
+ waitForBrowser = 70
48
45
 
49
- it 'sets an [up-href] attribute to the previous URL and sets the up-restore-scroll attribute to "true"', ->
50
- up.history.push('/one')
51
- up.history.push('/two')
52
- $element = up.hello(affix('a[href="/three"][up-back]').text('text'))
53
- expect($element.attr('href')).toEqualUrl('/three')
54
- expect($element.attr('up-href')).toEqualUrl('/one')
55
- expect($element.attr('up-restore-scroll')).toBe('')
56
- expect($element.attr('up-follow')).toBe('')
46
+ # By default, up.history will replace the <body> tag when
47
+ # the user presses the back-button. We reconfigure this
48
+ # so we don't lose the Jasmine runner interface.
49
+ up.history.config.popTargets = ['.container']
57
50
 
58
- it 'does not overwrite an existing up-href or up-restore-scroll attribute'
51
+ constructorSpy = jasmine.createSpy('constructor')
52
+ destructorSpy = jasmine.createSpy('destructor')
53
+
54
+ up.compiler '.example', ($example) ->
55
+ constructorSpy()
56
+ return destructorSpy
57
+
58
+ up.history.push('/one')
59
+ up.history.push('/two')
60
+
61
+ $container = affix('.container')
62
+ $example = $container.affix('.example')
63
+ up.hello($example)
64
+
65
+ expect(constructorSpy).toHaveBeenCalled()
66
+
67
+ history.back()
68
+ u.setTimer waitForBrowser, =>
69
+ expect(location.pathname).toEqual('/one')
70
+
71
+ @respondWith "<div class='container'>restored container text</div>"
72
+
73
+ u.nextFrame ->
74
+ expect(destructorSpy).toHaveBeenCalled()
75
+ done()
59
76
 
60
- it 'does not set an up-href attribute if there is no previous URL'
61
77
 
62
- describeFallback 'canPushState', ->
78
+ describe '[up-back]', ->
79
+
80
+ it 'sets an [up-href] attribute to the previous URL and sets the up-restore-scroll attribute to "true"', ->
81
+ up.history.push('/one')
82
+ up.history.push('/two')
83
+ $element = up.hello(affix('a[href="/three"][up-back]').text('text'))
84
+ expect($element.attr('href')).toEqualUrl('/three')
85
+ expect($element.attr('up-href')).toEqualUrl('/one')
86
+ expect($element.attr('up-restore-scroll')).toBe('')
87
+ expect($element.attr('up-follow')).toBe('')
88
+
89
+ it 'does not overwrite an existing up-href or up-restore-scroll attribute'
63
90
 
64
- it 'does not change the element', ->
65
- $element = up.hello(affix('a[href="/three"][up-back]').text('text'))
66
- expect($element.attr('up-href')).toBeUndefined()
91
+ it 'does not set an up-href attribute if there is no previous URL'
67
92
 
68
93
  describe 'scroll restoration', ->
69
94
 
70
- describeCapability 'canPushState', ->
95
+ afterEach ->
96
+ $('.viewport').remove()
71
97
 
72
- afterEach ->
73
- $('.viewport').remove()
98
+ it 'restores the scroll position of viewports when the user hits the back button', (done) ->
74
99
 
75
- it 'restores the scroll position of viewports when the user hits the back button', (done) ->
100
+ longContentHtml = """
101
+ <div class="viewport" style="width: 100px; height: 100px; overflow-y: scroll">
102
+ <div class="content" style="height: 1000px"></div>
103
+ </div>
104
+ """
76
105
 
77
- longContentHtml = """
78
- <div class="viewport" style="width: 100px; height: 100px; overflow-y: scroll">
79
- <div class="content" style="height: 1000px"></div>
80
- </div>
81
- """
106
+ respond = => @respondWith(longContentHtml)
82
107
 
83
- respond = => @respondWith(longContentHtml)
108
+ $viewport = $(longContentHtml).appendTo(document.body)
84
109
 
85
- $viewport = $(longContentHtml).appendTo(document.body)
110
+ up.layout.config.viewports = ['.viewport']
111
+ up.history.config.popTargets = ['.viewport']
86
112
 
87
- up.layout.config.viewports = ['.viewport']
88
- up.history.config.popTargets = ['.viewport']
113
+ up.replace('.content', '/one')
114
+ respond()
89
115
 
90
- up.replace('.content', '/one')
91
- respond()
116
+ $viewport.scrollTop(50)
92
117
 
93
- $viewport.scrollTop(50)
118
+ up.replace('.content', '/two')
119
+ respond()
94
120
 
95
- up.replace('.content', '/two')
96
- respond()
121
+ $('.viewport').scrollTop(150)
97
122
 
98
- $('.viewport').scrollTop(150)
123
+ up.replace('.content', '/three')
124
+ respond()
125
+ $('.viewport').scrollTop(250)
99
126
 
100
- up.replace('.content', '/three')
101
- respond()
102
- $('.viewport').scrollTop(250)
127
+ history.back()
128
+ u.setTimer 50, ->
129
+ respond() # we need to respond since we've never requested /two with the popTarget
130
+ expect($('.viewport').scrollTop()).toBe(150)
103
131
 
104
132
  history.back()
105
133
  u.setTimer 50, ->
106
- respond() # we need to respond since we've never requested /two with the popTarget
107
- expect($('.viewport').scrollTop()).toBe(150)
134
+ respond() # we need to respond since we've never requested /one with the popTarget
135
+ expect($('.viewport').scrollTop()).toBe(50)
108
136
 
109
- history.back()
137
+ history.forward()
110
138
  u.setTimer 50, ->
111
- respond() # we need to respond since we've never requested /one with the popTarget
112
- expect($('.viewport').scrollTop()).toBe(50)
139
+ # No need to respond since we requested /two with the popTarget
140
+ # when we went backwards
141
+ expect($('.viewport').scrollTop()).toBe(150)
113
142
 
114
143
  history.forward()
115
144
  u.setTimer 50, ->
116
- # No need to respond since we requested /two with the popTarget
117
- # when we went backwards
118
- expect($('.viewport').scrollTop()).toBe(150)
119
-
120
- history.forward()
121
- u.setTimer 50, ->
122
- respond() # we need to respond since we've never requested /three with the popTarget
123
- expect($('.viewport').scrollTop()).toBe(250)
124
- done()
125
-
126
- it 'restores the scroll position of two viewports marked with [up-viewport], but not configured in up.layout.config (bugfix)', (done) ->
127
- up.history.config.popTargets = ['.container']
128
-
129
- html = """
130
- <div class="container">
131
- <div class="viewport1" up-viewport style="width: 100px; height: 100px; overflow-y: scroll">
132
- <div class="content1" style="height: 5000px">content1</div>
133
- </div>
134
- <div class="viewport2" up-viewport style="width: 100px; height: 100px; overflow-y: scroll">
135
- <div class="content2" style="height: 5000px">content2</div>
136
- </div>
145
+ respond() # we need to respond since we've never requested /three with the popTarget
146
+ expect($('.viewport').scrollTop()).toBe(250)
147
+ done()
148
+
149
+ it 'restores the scroll position of two viewports marked with [up-viewport], but not configured in up.layout.config (bugfix)', (done) ->
150
+ up.history.config.popTargets = ['.container']
151
+
152
+ html = """
153
+ <div class="container">
154
+ <div class="viewport1" up-viewport style="width: 100px; height: 100px; overflow-y: scroll">
155
+ <div class="content1" style="height: 5000px">content1</div>
137
156
  </div>
138
- """
157
+ <div class="viewport2" up-viewport style="width: 100px; height: 100px; overflow-y: scroll">
158
+ <div class="content2" style="height: 5000px">content2</div>
159
+ </div>
160
+ </div>
161
+ """
139
162
 
140
- respond = => @respondWith(html)
163
+ respond = => @respondWith(html)
141
164
 
142
- $screen = affix('.screen')
143
- $screen.html(html)
165
+ $screen = affix('.screen')
166
+ $screen.html(html)
144
167
 
145
- up.replace('.content1, .content2', '/one', reveal: false)
146
- respond()
168
+ up.replace('.content1, .content2', '/one', reveal: false)
169
+ respond()
147
170
 
148
- $('.viewport1').scrollTop(3000)
149
- $('.viewport2').scrollTop(3050)
171
+ $('.viewport1').scrollTop(3000)
172
+ $('.viewport2').scrollTop(3050)
150
173
 
151
- expect('.viewport1').toBeScrolledTo(3000)
152
- expect('.viewport2').toBeScrolledTo(3050)
174
+ expect('.viewport1').toBeScrolledTo(3000)
175
+ expect('.viewport2').toBeScrolledTo(3050)
153
176
 
154
- up.replace('.content1, .content2', '/two', reveal: false)
155
- respond()
177
+ up.replace('.content1, .content2', '/two', reveal: false)
178
+ respond()
156
179
 
157
- u.setTimer 50, ->
180
+ u.setTimer 50, ->
158
181
 
159
- expect(location.href).toEqualUrl('/two')
182
+ expect(location.href).toEqualUrl('/two')
160
183
 
161
- history.back()
184
+ history.back()
162
185
 
163
- u.setTimer 50, ->
164
- # we need to respond since we've never requested the original URL with the popTarget
165
- respond()
186
+ u.setTimer 50, ->
187
+ # we need to respond since we've never requested the original URL with the popTarget
188
+ respond()
166
189
 
167
- u.nextFrame ->
168
- expect('.viewport1').toBeScrolledTo(3000)
169
- expect('.viewport2').toBeScrolledTo(3050)
170
- done()
190
+ u.nextFrame ->
191
+ expect('.viewport1').toBeScrolledTo(3000)
192
+ expect('.viewport2').toBeScrolledTo(3050)
193
+ done()
171
194
 
172
195
 
173
196
  describe 'events', ->
174
197
 
175
- describeCapability 'canPushState', ->
198
+ it 'emits up:history:* events as the user goes forwards and backwards through history', (done) ->
199
+ up.proxy.config.cacheSize = 0
200
+ up.history.config.popTargets = ['.viewport']
176
201
 
177
- it 'emits up:history:* events as the user goes forwards and backwards through history', (done) ->
178
- up.proxy.config.cacheSize = 0
179
- up.history.config.popTargets = ['.viewport']
202
+ affix('.viewport .content')
203
+ respond = =>
204
+ @respondWith """
205
+ <div class="viewport">
206
+ <div class="content">content</div>
207
+ </div>
208
+ """
180
209
 
181
- affix('.viewport .content')
182
- respond = =>
183
- @respondWith """
184
- <div class="viewport">
185
- <div class="content">content</div>
186
- </div>
187
- """
210
+ events = []
211
+ u.each ['up:history:pushed', 'up:history:restored'], (eventName) ->
212
+ up.on eventName, (event) ->
213
+ events.push [eventName, event.url]
188
214
 
189
- events = []
190
- u.each ['up:history:pushed', 'up:history:restored'], (eventName) ->
191
- up.on eventName, (event) ->
192
- events.push [eventName, event.url]
215
+ normalize = up.history.normalizeUrl
193
216
 
194
- normalize = up.history.normalizeUrl
217
+ up.replace('.content', '/one')
218
+ respond()
195
219
 
196
- up.replace('.content', '/one')
197
- respond()
220
+ expect(events).toEqual [
221
+ ['up:history:pushed', normalize('/one')]
222
+ ]
198
223
 
199
- expect(events).toEqual [
200
- ['up:history:pushed', normalize('/one')]
201
- ]
224
+ up.replace('.content', '/two')
225
+ respond()
202
226
 
203
- up.replace('.content', '/two')
204
- respond()
227
+ expect(events).toEqual [
228
+ ['up:history:pushed', normalize('/one')]
229
+ ['up:history:pushed', normalize('/two')]
230
+ ]
205
231
 
206
- expect(events).toEqual [
207
- ['up:history:pushed', normalize('/one')]
208
- ['up:history:pushed', normalize('/two')]
209
- ]
232
+ up.replace('.content', '/three')
233
+ respond()
234
+
235
+ expect(events).toEqual [
236
+ ['up:history:pushed', normalize('/one')]
237
+ ['up:history:pushed', normalize('/two')]
238
+ ['up:history:pushed', normalize('/three')]
239
+ ]
210
240
 
211
- up.replace('.content', '/three')
241
+ history.back()
242
+ u.setTimer 50, ->
212
243
  respond()
213
244
 
214
245
  expect(events).toEqual [
215
246
  ['up:history:pushed', normalize('/one')]
216
247
  ['up:history:pushed', normalize('/two')]
217
248
  ['up:history:pushed', normalize('/three')]
249
+ ['up:history:restored', normalize('/two')]
218
250
  ]
219
251
 
220
252
  history.back()
@@ -226,9 +258,10 @@ describe 'up.history', ->
226
258
  ['up:history:pushed', normalize('/two')]
227
259
  ['up:history:pushed', normalize('/three')]
228
260
  ['up:history:restored', normalize('/two')]
261
+ ['up:history:restored', normalize('/one')]
229
262
  ]
230
263
 
231
- history.back()
264
+ history.forward()
232
265
  u.setTimer 50, ->
233
266
  respond()
234
267
 
@@ -238,11 +271,12 @@ describe 'up.history', ->
238
271
  ['up:history:pushed', normalize('/three')]
239
272
  ['up:history:restored', normalize('/two')]
240
273
  ['up:history:restored', normalize('/one')]
274
+ ['up:history:restored', normalize('/two')]
241
275
  ]
242
276
 
243
277
  history.forward()
244
278
  u.setTimer 50, ->
245
- respond()
279
+ respond() # we need to respond since we've never requested /three with the popTarget
246
280
 
247
281
  expect(events).toEqual [
248
282
  ['up:history:pushed', normalize('/one')]
@@ -251,20 +285,7 @@ describe 'up.history', ->
251
285
  ['up:history:restored', normalize('/two')]
252
286
  ['up:history:restored', normalize('/one')]
253
287
  ['up:history:restored', normalize('/two')]
288
+ ['up:history:restored', normalize('/three')]
254
289
  ]
255
290
 
256
- history.forward()
257
- u.setTimer 50, ->
258
- respond() # we need to respond since we've never requested /three with the popTarget
259
-
260
- expect(events).toEqual [
261
- ['up:history:pushed', normalize('/one')]
262
- ['up:history:pushed', normalize('/two')]
263
- ['up:history:pushed', normalize('/three')]
264
- ['up:history:restored', normalize('/two')]
265
- ['up:history:restored', normalize('/one')]
266
- ['up:history:restored', normalize('/two')]
267
- ['up:history:restored', normalize('/three')]
268
- ]
269
-
270
- done()
291
+ done()
@@ -365,34 +365,92 @@ describe 'up.link', ->
365
365
  expect($('.target')).toHaveText('new text')
366
366
  expect(location.pathname).toEqual('/other/path')
367
367
 
368
- it 'prefers to update a container in the same layer as the clicked link', (done) ->
369
- up.motion.config.enabled = false
368
+ describe 'choice of target layer', ->
370
369
 
371
- $popupOpener = affix('a[href="/popup"]')
372
- up.popup.attach($popupOpener, html: "<div class='target'>old popup text</div>", target: '.target')
373
- affix('.document').affix('.target').text('old document text')
370
+ beforeEach ->
371
+ up.motion.config.enabled = false
374
372
 
375
- $linkInDocument = affix('a[href="/foo"][up-target=".target"]')
376
- $linkInPopup = $('.up-popup').affix('a[href="/bar"][up-target=".target"]')
373
+ it 'prefers to update a container in the same layer as the clicked link', (done) ->
374
+ affix('.document').affix('.target').text('old document text')
375
+ up.modal.extract('.target', "<div class='target'>old modal text</div>")
377
376
 
378
- expect($('.document .target')).toHaveText('old document text')
379
- expect($('.up-popup .target')).toHaveText('old popup text')
377
+ u.nextFrame =>
378
+ expect($('.document .target')).toHaveText('old document text')
379
+ expect($('.up-modal .target')).toHaveText('old modal text')
380
380
 
381
- u.nextFrame =>
381
+ $linkInModal = $('.up-modal').affix('a[href="/bar"][up-target=".target"]')
382
+ Trigger.clickSequence($linkInModal)
382
383
 
383
- Trigger.clickSequence($linkInPopup)
384
+ u.nextFrame =>
385
+ @respondWith '<div class="target">new text from modal link</div>'
384
386
 
385
- u.nextFrame =>
386
- @respondWith '<div class="target">new text from popup link</div>'
387
+ expect($('.document .target')).toHaveText('old document text')
388
+ expect($('.up-modal .target')).toHaveText('new text from modal link')
387
389
 
388
- expect($('.document .target')).toHaveText('old document text')
389
- expect($('.up-popup .target')).toHaveText('new text from popup link')
390
- Trigger.clickSequence($linkInDocument)
390
+ done()
391
+
392
+ describe 'with [up-layer] modifier', ->
393
+
394
+ it 'allows to name a layer for the update', (done) ->
395
+ affix('.document').affix('.target').text('old document text')
396
+ up.modal.extract('.target', "<div class='target'>old modal text</div>", sticky: true)
391
397
 
392
398
  u.nextFrame =>
393
- @respondWith '<div class="target">new text from document link</div>'
394
- expect($('.document .target')).toHaveText('new text from document link')
395
- done()
399
+ expect($('.document .target')).toHaveText('old document text')
400
+ expect($('.up-modal .target')).toHaveText('old modal text')
401
+
402
+ $linkInModal = $('.up-modal').affix('a[href="/bar"][up-target=".target"][up-layer="page"]')
403
+ Trigger.clickSequence($linkInModal)
404
+
405
+ u.nextFrame =>
406
+ @respondWith '<div class="target">new text from modal link</div>'
407
+
408
+ expect($('.document .target')).toHaveText('new text from modal link')
409
+ expect($('.up-modal .target')).toHaveText('old modal text')
410
+
411
+ done()
412
+
413
+ it 'ignores [up-layer] if the server responds with a non-200 status code', (done) ->
414
+ affix('.document').affix('.target').text('old document text')
415
+ up.modal.extract('.target', "<div class='target'>old modal text</div>", sticky: true)
416
+
417
+ u.nextFrame =>
418
+ expect($('.document .target')).toHaveText('old document text')
419
+ expect($('.up-modal .target')).toHaveText('old modal text')
420
+
421
+ $linkInModal = $('.up-modal').affix('a[href="/bar"][up-target=".target"][up-fail-target=".target"][up-layer="page"]')
422
+ Trigger.clickSequence($linkInModal)
423
+
424
+ u.nextFrame =>
425
+ @respondWith
426
+ responseText: '<div class="target">new failure text from modal link</div>'
427
+ status: 500
428
+
429
+ expect($('.document .target')).toHaveText('old document text')
430
+ expect($('.up-modal .target')).toHaveText('new failure text from modal link')
431
+
432
+ done()
433
+
434
+ it 'allows to name a layer for a non-200 response using an [up-fail-layer] modifier', (done) ->
435
+ affix('.document').affix('.target').text('old document text')
436
+ up.modal.extract('.target', "<div class='target'>old modal text</div>", sticky: true)
437
+
438
+ u.nextFrame =>
439
+ expect($('.document .target')).toHaveText('old document text')
440
+ expect($('.up-modal .target')).toHaveText('old modal text')
441
+
442
+ $linkInModal = $('.up-modal').affix('a[href="/bar"][up-target=".target"][up-fail-target=".target"][up-fail-layer="page"]')
443
+ Trigger.clickSequence($linkInModal)
444
+
445
+ u.nextFrame =>
446
+ @respondWith
447
+ responseText: '<div class="target">new failure text from modal link</div>'
448
+ status: 500
449
+
450
+ expect($('.document .target')).toHaveText('new failure text from modal link')
451
+ expect($('.up-modal .target')).toHaveText('old modal text')
452
+
453
+ done()
396
454
 
397
455
  describe 'with [up-fail-target] modifier', ->
398
456
 
@@ -28,7 +28,7 @@ describe 'up.syntax', ->
28
28
  up.destroy('.container')
29
29
  expect(destructor).toHaveBeenCalled()
30
30
 
31
- it 'allows compilers to return an array of functions to clal when the compiled element is destroyed', ->
31
+ it 'allows compilers to return an array of functions to all when the compiled element is destroyed', ->
32
32
  destructor1 = jasmine.createSpy('destructor1')
33
33
  destructor2 = jasmine.createSpy('destructor2')
34
34
  up.compiler '.child', ($element) ->
@@ -688,6 +688,40 @@ describe 'up.util', ->
688
688
  array = [1, [2, [3,4]], 5]
689
689
  expect(u.flatten(array)).toEqual([1, 2, [3, 4], 5])
690
690
 
691
+ describe 'up.util.renameKey', ->
692
+
693
+ it 'renames a key in the given property', ->
694
+ object = { a: 'a value', b: 'b value'}
695
+ u.renameKey(object, 'a', 'c')
696
+ expect(object.a).toBeUndefined()
697
+ expect(object.b).toBe('b value')
698
+ expect(object.c).toBe('a value')
699
+
700
+ describe 'up.util.findWithSelf', ->
701
+
702
+ it 'finds the selector in descendants of the given element', ->
703
+ $container = affix('div')
704
+ $child1 = $container.affix('div.match')
705
+ $child2 = $container.affix('div')
706
+ $child2Child1 = $child2.affix('div.match')
707
+ matches = u.findWithSelf($container, '.match')
708
+ expect(matches).toEqual [$child1.get(0), $child2Child1.get(0)]
709
+
710
+ it 'finds the element itself if the element matches the given selector', ->
711
+ $container = affix('div.match')
712
+ $child1 = $container.affix('div')
713
+ $child1Child1 = $child1.affix('div.match')
714
+ matches = u.findWithSelf($container, '.match')
715
+ expect(matches).toEqual [$container.get(0), $child1Child1.get(0)]
716
+
717
+ it 'returns multiple matches in the same subtree', ->
718
+ $container = affix('div.match')
719
+ $child1 = $container.affix('div')
720
+ $child2 = $container.affix('div.match')
721
+ $child2Child1 = $child2.affix('div.match')
722
+ matches = u.findWithSelf($container, '.match')
723
+ expect(matches).toEqual [$container.get(0), $child2.get(0), $child2Child1.get(0)]
724
+
691
725
  describe 'up.util.memoize', ->
692
726
 
693
727
  it 'returns a function that calls the memoized function', ->
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.36.2
4
+ version: 0.37.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: 2017-07-03 00:00:00.000000000 Z
11
+ date: 2017-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -157,6 +157,7 @@ files:
157
157
  - spec_app/app/controllers/form_test/basics_controller.rb
158
158
  - spec_app/app/controllers/form_test/uploads_controller.rb
159
159
  - spec_app/app/controllers/pages_controller.rb
160
+ - spec_app/app/controllers/replace_test_controller.rb
160
161
  - spec_app/app/helpers/application_helper.rb
161
162
  - spec_app/app/mailers/.keep
162
163
  - spec_app/app/models/concerns/.keep
@@ -173,6 +174,9 @@ files:
173
174
  - spec_app/app/views/form_test/uploads/new.erb
174
175
  - spec_app/app/views/layouts/integration_test.erb
175
176
  - spec_app/app/views/pages/start.erb
177
+ - spec_app/app/views/replace_test/_nav.erb
178
+ - spec_app/app/views/replace_test/page1.erb
179
+ - spec_app/app/views/replace_test/page2.erb
176
180
  - spec_app/bin/bundle
177
181
  - spec_app/bin/rails
178
182
  - spec_app/bin/rake