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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -1
- data/dist/unpoly.js +704 -446
- data/dist/unpoly.min.js +3 -3
- data/lib/assets/javascripts/unpoly/browser.js.coffee +18 -9
- data/lib/assets/javascripts/unpoly/bus.js.coffee +28 -1
- data/lib/assets/javascripts/unpoly/flow.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/history.js.coffee +54 -22
- data/lib/assets/javascripts/unpoly/link.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/log.js.coffee +19 -12
- data/lib/assets/javascripts/unpoly/modal.js.coffee +119 -124
- data/lib/assets/javascripts/unpoly/motion.js.coffee +1 -0
- data/lib/assets/javascripts/unpoly/navigation.js.coffee +2 -6
- data/lib/assets/javascripts/unpoly/popup.js.coffee +136 -126
- data/lib/assets/javascripts/unpoly/proxy.js.coffee +0 -2
- data/lib/assets/javascripts/unpoly/syntax.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/tooltip.js.coffee +101 -46
- data/lib/assets/javascripts/unpoly/util.js.coffee +76 -7
- data/lib/unpoly/rails/version.rb +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/app/assets/stylesheets/integration_test.sass +4 -0
- data/spec_app/app/assets/stylesheets/jasmine_specs.sass +5 -0
- data/spec_app/app/views/css_test/modal.erb +3 -0
- data/spec_app/app/views/css_test/modal_contents.erb +5 -0
- data/spec_app/app/views/css_test/popup.erb +11 -11
- data/spec_app/app/views/css_test/tooltip.erb +12 -5
- data/spec_app/app/views/pages/start.erb +4 -0
- data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +2 -3
- data/spec_app/spec/javascripts/up/flow_spec.js.coffee +97 -88
- data/spec_app/spec/javascripts/up/history_spec.js.coffee +100 -1
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +18 -16
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +102 -97
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +89 -75
- data/spec_app/spec/javascripts/up/navigation_spec.js.coffee +17 -5
- data/spec_app/spec/javascripts/up/popup_spec.js.coffee +89 -70
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +23 -0
- 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
|
-
|
106
|
-
|
107
|
-
|
108
|
-
expect($
|
109
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
113
|
-
|
114
|
-
up.
|
115
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
124
|
-
|
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
|
-
|
129
|
-
|
130
|
-
|
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
|
-
|
112
|
+
up.popup.attach($span, { target: '.target', html: '<div class="target">response2</div>' })
|
141
113
|
|
142
|
-
|
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
|
-
|
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()).
|
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()).
|
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('
|
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
|
-
$
|
260
|
-
$link =
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
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.
|
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-
|
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
|