unpoly-rails 0.26.2 → 0.27.0

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.

Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -1
  3. data/dist/unpoly.js +704 -446
  4. data/dist/unpoly.min.js +3 -3
  5. data/lib/assets/javascripts/unpoly/browser.js.coffee +18 -9
  6. data/lib/assets/javascripts/unpoly/bus.js.coffee +28 -1
  7. data/lib/assets/javascripts/unpoly/flow.js.coffee +1 -1
  8. data/lib/assets/javascripts/unpoly/history.js.coffee +54 -22
  9. data/lib/assets/javascripts/unpoly/link.js.coffee +1 -1
  10. data/lib/assets/javascripts/unpoly/log.js.coffee +19 -12
  11. data/lib/assets/javascripts/unpoly/modal.js.coffee +119 -124
  12. data/lib/assets/javascripts/unpoly/motion.js.coffee +1 -0
  13. data/lib/assets/javascripts/unpoly/navigation.js.coffee +2 -6
  14. data/lib/assets/javascripts/unpoly/popup.js.coffee +136 -126
  15. data/lib/assets/javascripts/unpoly/proxy.js.coffee +0 -2
  16. data/lib/assets/javascripts/unpoly/syntax.js.coffee +1 -1
  17. data/lib/assets/javascripts/unpoly/tooltip.js.coffee +101 -46
  18. data/lib/assets/javascripts/unpoly/util.js.coffee +76 -7
  19. data/lib/unpoly/rails/version.rb +1 -1
  20. data/spec_app/Gemfile.lock +1 -1
  21. data/spec_app/app/assets/stylesheets/integration_test.sass +4 -0
  22. data/spec_app/app/assets/stylesheets/jasmine_specs.sass +5 -0
  23. data/spec_app/app/views/css_test/modal.erb +3 -0
  24. data/spec_app/app/views/css_test/modal_contents.erb +5 -0
  25. data/spec_app/app/views/css_test/popup.erb +11 -11
  26. data/spec_app/app/views/css_test/tooltip.erb +12 -5
  27. data/spec_app/app/views/pages/start.erb +4 -0
  28. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +2 -3
  29. data/spec_app/spec/javascripts/up/flow_spec.js.coffee +97 -88
  30. data/spec_app/spec/javascripts/up/history_spec.js.coffee +100 -1
  31. data/spec_app/spec/javascripts/up/link_spec.js.coffee +18 -16
  32. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +102 -97
  33. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +89 -75
  34. data/spec_app/spec/javascripts/up/navigation_spec.js.coffee +17 -5
  35. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +89 -70
  36. data/spec_app/spec/javascripts/up/util_spec.js.coffee +23 -0
  37. metadata +4 -2
@@ -24,6 +24,16 @@ describe 'up.navigation', ->
24
24
  expect($currentLink).toHaveClass('up-current')
25
25
  expect($otherLink).not.toHaveClass('up-current')
26
26
 
27
+ it 'matches the current and destination URLs if they only differ by a trailing slash', ->
28
+ spyOn(up.browser, 'url').and.returnValue('/foo')
29
+ $currentLink = up.hello(affix('span[up-href="/foo/"]'))
30
+ expect($currentLink).toHaveClass('up-current')
31
+
32
+ it 'does not match the current and destination URLs if they differ in the search', ->
33
+ spyOn(up.browser, 'url').and.returnValue('/foo?q=1')
34
+ $currentLink = up.hello(affix('span[up-href="/foo?q=2"]'))
35
+ expect($currentLink).not.toHaveClass('up-current')
36
+
27
37
  it 'marks any link as .up-current if any of its space-separated up-alias values matches the current URL', ->
28
38
  spyOn(up.browser, 'url').and.returnValue('/foo')
29
39
  $currentLink = up.hello(affix('a[href="/x"][up-alias="/aaa /foo /bbb"]'))
@@ -102,11 +112,13 @@ describe 'up.navigation', ->
102
112
  expect($popupLink).toHaveClass('up-current')
103
113
  expect($unrelatedLink).not.toHaveClass('up-current')
104
114
 
105
- up.popup.close().then ->
106
- expect($backgroundLink).toHaveClass('up-current')
107
- expect($popupLink).not.toHaveClass('up-current')
108
- expect($unrelatedLink).not.toHaveClass('up-current')
109
- done()
115
+ done()
116
+
117
+ # up.popup.close().then ->
118
+ # expect($backgroundLink).toHaveClass('up-current')
119
+ # expect($popupLink).not.toHaveClass('up-current')
120
+ # expect($unrelatedLink).not.toHaveClass('up-current')
121
+ # done()
110
122
 
111
123
  it 'changes .up-current marks as the URL changes'
112
124
 
@@ -77,75 +77,53 @@ describe 'up.popup', ->
77
77
 
78
78
  describe 'with { html } option', ->
79
79
 
80
- it 'extracts the selector from the given HTML string', ->
80
+ it 'extracts the selector from the given HTML string', (done) ->
81
81
  $span = affix('span')
82
- up.popup.attach($span, target: '.container', html: "<div class='container'>container contents</div>")
83
- expect($('.up-popup')).toHaveText('container contents')
82
+ up.popup.attach($span, target: '.container', html: "<div class='container'>container contents</div>").then ->
83
+ expect($('.up-popup')).toHaveText('container contents')
84
+ done()
84
85
 
85
86
  describe 'opening a popup while another modal is open', ->
86
87
 
87
- it 'does not open multiple popups or pad the body twice if the user starts loading a second popup before the first was done loading', (done) ->
88
- $span = affix('span')
89
- up.popup.config.closeDuration = 10
90
- promise1 = up.popup.attach($span, url: '/path1', target: '.container', animation: 'fade-in', duration: 100)
91
- promise2 = up.popup.attach($span, url: '/path2', target: '.container', animation: 'fade-in', duration: 100)
92
- expect(jasmine.Ajax.requests.count()).toBe(2)
93
- request1 = jasmine.Ajax.requests.at(0)
94
- request2 = jasmine.Ajax.requests.at(1)
95
-
96
- u.setTimer 10, =>
97
- @respondWith('<div class="container">response1</div>', request: request1)
98
- u.setTimer 10, =>
99
- @respondWith('<div class="container">response2</div>', request: request2)
100
- u.setTimer 30, =>
101
- expect($('.up-popup').length).toBe(1)
102
- expect($('.container')).toHaveText('response2')
103
- done()
104
-
105
- it 'closes the current popup and wait for its close animation to finish before starting the open animation of a second popup', (done) ->
106
- $span = affix('span')
107
- up.popup.config.openAnimation = 'fade-in'
108
- up.popup.config.openDuration = 5
109
- up.popup.config.closeAnimation = 'fade-out'
110
- up.popup.config.closeDuration = 50
88
+ describeCapability 'canCssTransition', ->
111
89
 
112
- events = []
113
- u.each ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed'], (event) ->
114
- up.on event, ->
115
- events.push(event)
90
+ it 'closes the current popup and wait for its close animation to finish before starting the open animation of a second popup', (done) ->
91
+ $span = affix('span')
92
+ up.popup.config.openAnimation = 'fade-in'
93
+ up.popup.config.openDuration = 5
94
+ up.popup.config.closeAnimation = 'fade-out'
95
+ up.popup.config.closeDuration = 50
116
96
 
117
- up.popup.attach($span, { target: '.target', html: '<div class="target">response1</div>' })
97
+ events = []
98
+ u.each ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed'], (event) ->
99
+ up.on event, -> events.push(event)
118
100
 
119
- # First popup is starting opening animation
120
- expect(events).toEqual ['up:popup:open']
121
- expect($('.target')).toHaveText('response1')
101
+ up.popup.attach($span, { target: '.target', html: '<div class="target">response1</div>' })
122
102
 
123
- u.setTimer 30, ->
124
- # First popup has completed opening animation
125
- expect(events).toEqual ['up:popup:open', 'up:popup:opened']
103
+ # First popup is starting opening animation
104
+ expect(events).toEqual ['up:popup:open']
126
105
  expect($('.target')).toHaveText('response1')
127
106
 
128
- up.popup.attach($span, { target: '.target', html: '<div class="target">response2</div>' })
129
-
130
- # First popup is starting close animation. Second popup waits for that.
131
- expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:open', 'up:popup:close']
132
- expect($('.target')).toHaveText('response1')
133
-
134
- u.setTimer 15, ->
135
-
136
- # Second popup is still waiting for first popup's closing animaton to finish.
137
- expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:open', 'up:popup:close']
107
+ u.setTimer 30, ->
108
+ # First popup has completed opening animation
109
+ expect(events).toEqual ['up:popup:open', 'up:popup:opened']
138
110
  expect($('.target')).toHaveText('response1')
139
111
 
140
- u.setTimer 100, ->
112
+ up.popup.attach($span, { target: '.target', html: '<div class="target">response2</div>' })
141
113
 
142
- # First popup has finished closing, second popup has finished opening.
143
- expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:open', 'up:popup:close', 'up:popup:closed', 'up:popup:opened']
144
- expect($('.target')).toHaveText('response2')
114
+ u.setTimer 15, ->
145
115
 
146
- done()
116
+ # Second popup is still waiting for first popup's closing animation to finish.
117
+ expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:close']
118
+ expect($('.target')).toHaveText('response1')
147
119
 
120
+ u.setTimer 100, ->
148
121
 
122
+ # First popup has finished closing, second popup has finished opening.
123
+ expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed', 'up:popup:open', 'up:popup:opened']
124
+ expect($('.target')).toHaveText('response2')
125
+
126
+ done()
149
127
 
150
128
  describe 'up.popup.coveredUrl', ->
151
129
 
@@ -153,14 +131,14 @@ describe 'up.popup', ->
153
131
 
154
132
  it 'returns the URL behind the popup', (done) ->
155
133
  up.history.replace('/foo')
156
- expect(up.popup.coveredUrl()).toBeUndefined()
134
+ expect(up.popup.coveredUrl()).toBeMissing()
157
135
 
158
136
  $popupLink = affix('a[href="/bar"][up-popup=".container"]')
159
137
  $popupLink.click()
160
138
  @respondWith('<div class="container">text</div>')
161
139
  expect(up.popup.coveredUrl()).toEndWith('/foo')
162
140
  up.popup.close().then ->
163
- expect(up.popup.coveredUrl()).toBeUndefined()
141
+ expect(up.popup.coveredUrl()).toBeMissing()
164
142
  done()
165
143
 
166
144
  describe 'up.popup.close', ->
@@ -178,7 +156,7 @@ describe 'up.popup', ->
178
156
  beforeEach ->
179
157
  @stubAttach = =>
180
158
  @$link = affix('a[href="/path"][up-popup=".target"]')
181
- @attachSpy = up.popup.knife.mock('attach').and.returnValue(u.resolvedPromise())
159
+ @attachSpy = up.popup.knife.mock('attachAsap').and.returnValue(u.resolvedPromise())
182
160
  @defaultSpy = up.link.knife.mock('allowDefault').and.callFake((event) -> event.preventDefault())
183
161
 
184
162
  it 'opens the clicked link in a popup', ->
@@ -208,6 +186,30 @@ describe 'up.popup', ->
208
186
  Trigger.click(@$link, metaKey: true)
209
187
  expect(@attachSpy).not.toHaveBeenCalled()
210
188
 
189
+ it 'closes an existing popup before opening the new popup', ->
190
+
191
+ up.popup.config.openDuration = 0
192
+ up.popup.config.closeDuration = 0
193
+
194
+ $link1 = affix('a[href="/path1"][up-popup=".target"]')
195
+ $link2 = affix('a[href="/path2"][up-popup=".target"]')
196
+
197
+ events = []
198
+ u.each ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed'], (event) ->
199
+ up.on event, -> events.push(event)
200
+
201
+ Trigger.click($link1)
202
+ expect(events).toEqual ['up:popup:open']
203
+ @respondWith('<div class="target">text1</div>')
204
+ expect(events).toEqual ['up:popup:open', 'up:popup:opened']
205
+
206
+ Trigger.click($link2)
207
+ expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed', 'up:popup:open']
208
+ @respondWith('<div class="target">text1</div>')
209
+
210
+ expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed', 'up:popup:open', 'up:popup:opened']
211
+
212
+
211
213
  describe 'with [up-instant] modifier', ->
212
214
 
213
215
  beforeEach ->
@@ -255,20 +257,24 @@ describe 'up.popup', ->
255
257
 
256
258
  describe 'when clicked inside a popup', ->
257
259
 
258
- it 'closes the open popup and prevents the default action', ->
259
- $popup = affix('.up-popup')
260
- $link = $popup.affix('a[up-close]') # link is within the popup
261
- up.hello($link)
262
- wasDefaultPrevented = false
263
- wasClosed = false
264
- up.on 'click', 'a[up-close]', (event) ->
265
- wasDefaultPrevented = event.isDefaultPrevented()
266
- true # the line above might return false and cancel propagation / prevent default
267
- up.on 'up:popup:close', ->
268
- wasClosed = true
269
- $link.click()
270
- expect(wasClosed).toBe(true)
271
- expect(wasDefaultPrevented).toBe(true)
260
+ it 'closes the open popup and prevents the default action', (done) ->
261
+ $link = affix('a')
262
+ up.popup.attach($link, html: '<div class="target">text</div>', target: '.target').then ->
263
+ $popup = affix('.up-popup')
264
+ $link = $popup.affix('a[up-close]') # link is within the popup
265
+ up.hello($link)
266
+ wasDefaultPrevented = false
267
+ wasClosed = false
268
+ up.on 'click', 'a[up-close]', (event) ->
269
+ wasDefaultPrevented = event.isDefaultPrevented()
270
+ true # the line above might return false and cancel propagation / prevent default
271
+ up.on 'up:popup:close', ->
272
+ wasClosed = true
273
+ $link.click()
274
+ u.nextFrame ->
275
+ expect(wasClosed).toBe(true)
276
+ expect(wasDefaultPrevented).toBe(true)
277
+ done()
272
278
 
273
279
  describe 'when no popup is open', ->
274
280
 
@@ -336,3 +342,16 @@ describe 'up.popup', ->
336
342
  up.extract('.inside', "<div class='inside'>new inside</div>", origin: $('.outside'))
337
343
  expect($('.inside')).toHaveText('new inside')
338
344
  expect($('.up-popup')).toExist()
345
+
346
+ describe 'when clicking on the body', ->
347
+
348
+ beforeEach ->
349
+ up.motion.config.enabled = false
350
+
351
+ it 'closes a popup on mousedown (in case an [up-instant] link removes its parent and thus a click event never fires)', ->
352
+ affix('.outside').text('old outside')
353
+ $link = affix('.link')
354
+ up.popup.attach($link, href: '/path', target: '.inside')
355
+ @respondWith("<div class='inside'>inside</div>")
356
+ Trigger.mousedown($('body'))
357
+ expect($('.up-popup')).not.toExist()
@@ -2,6 +2,15 @@ describe 'up.util', ->
2
2
 
3
3
  describe 'Javascript functions', ->
4
4
 
5
+ describe 'up.util.cssAnimate', ->
6
+
7
+ it 'returns a deferred that eventually resolves if called with a duration of 0 (bugfix)', (done) ->
8
+ $element = affix('.element')
9
+ promise = up.util.cssAnimate($element, { 'font-size': '90px' }, { duration: 0 })
10
+ promise.then ->
11
+ expect('done').toEqual('done') # need an expectation of Jasmine will complain
12
+ done()
13
+
5
14
  describe 'up.util.isFixed', ->
6
15
 
7
16
  it 'returns true if the given element or one of its ancestors has a "fixed" CSS position', ->
@@ -286,6 +295,20 @@ describe 'up.util', ->
286
295
  string = up.util.requestDataAsQuery({ 'my+key': 'my+value' })
287
296
  expect(string).toEqual('my%2Bkey=my%2Bvalue')
288
297
 
298
+ describe 'up.util.unresolvableDeferred', ->
299
+
300
+ it 'returns a different object every time (to prevent memory leaks)', ->
301
+ one = up.util.unresolvableDeferred()
302
+ two = up.util.unresolvableDeferred()
303
+ expect(one).not.toBe(two)
304
+
305
+ describe 'up.util.unresolvablePromise', ->
306
+
307
+ it 'returns a different object every time (to prevent memory leaks)', ->
308
+ one = up.util.unresolvablePromise()
309
+ two = up.util.unresolvablePromise()
310
+ expect(one).not.toBe(two)
311
+
289
312
  describe 'up.util.resolvableWhen', ->
290
313
 
291
314
  it 'returns a promise that is resolved when all the given deferreds are resolved', ->
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.26.2
4
+ version: 0.27.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-06-16 00:00:00.000000000 Z
11
+ date: 2016-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -150,6 +150,8 @@ files:
150
150
  - spec_app/app/helpers/application_helper.rb
151
151
  - spec_app/app/mailers/.keep
152
152
  - spec_app/app/models/concerns/.keep
153
+ - spec_app/app/views/css_test/modal.erb
154
+ - spec_app/app/views/css_test/modal_contents.erb
153
155
  - spec_app/app/views/css_test/popup.erb
154
156
  - spec_app/app/views/css_test/popup_contents.erb
155
157
  - spec_app/app/views/css_test/tooltip.erb