unpoly-rails 0.24.1 → 0.25.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 +31 -0
- data/README_RAILS.md +8 -1
- data/dist/unpoly.css +22 -10
- data/dist/unpoly.js +406 -196
- data/dist/unpoly.min.css +1 -1
- data/dist/unpoly.min.js +3 -3
- data/lib/assets/javascripts/unpoly/flow.js.coffee +36 -19
- data/lib/assets/javascripts/unpoly/form.js.coffee +1 -2
- data/lib/assets/javascripts/unpoly/link.js.coffee +2 -2
- data/lib/assets/javascripts/unpoly/modal.js.coffee +174 -81
- data/lib/assets/javascripts/unpoly/navigation.js.coffee +3 -1
- data/lib/assets/javascripts/unpoly/popup.js.coffee +62 -37
- data/lib/assets/javascripts/unpoly/proxy.js.coffee +1 -0
- data/lib/assets/javascripts/unpoly/syntax.js.coffee +12 -4
- data/lib/assets/javascripts/unpoly/util.js.coffee +55 -13
- data/lib/assets/stylesheets/unpoly/modal.css.sass +28 -12
- data/lib/unpoly/rails/inspector.rb +26 -0
- data/lib/unpoly/rails/version.rb +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/app/controllers/binding_test_controller.rb +6 -0
- data/spec_app/spec/controllers/binding_test_controller_spec.rb +82 -11
- data/spec_app/spec/javascripts/up/flow_spec.js.coffee +21 -7
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +15 -0
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +11 -10
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +232 -30
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +33 -27
- data/spec_app/spec/javascripts/up/popup_spec.js.coffee +72 -0
- data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +51 -13
- metadata +2 -2
@@ -47,50 +47,230 @@ describe 'up.modal', ->
|
|
47
47
|
|
48
48
|
describe 'up.modal.visit', ->
|
49
49
|
|
50
|
-
|
51
|
-
promise = up.modal.visit('/foo', target: '.container')
|
50
|
+
describe 'preventing elements from jumping as scrollbars change', ->
|
52
51
|
|
53
|
-
|
52
|
+
it "brings its own scrollbar, padding the body on the right", (done) ->
|
53
|
+
promise = up.modal.visit('/foo', target: '.container')
|
54
54
|
|
55
|
-
|
55
|
+
@respondWith('<div class="container">text</div>')
|
56
|
+
|
57
|
+
promise.then ->
|
58
|
+
$modal = $('.up-modal')
|
59
|
+
$viewport = $modal.find('.up-modal-viewport')
|
60
|
+
$body = $('body')
|
61
|
+
expect($modal).toExist()
|
62
|
+
expect($viewport.css('overflow-y')).toEqual('scroll')
|
63
|
+
expect($body.css('overflow-y')).toEqual('hidden')
|
64
|
+
expect(parseInt($body.css('padding-right'))).toBeAround(assumedScrollbarWidth, 5)
|
65
|
+
|
66
|
+
up.modal.close().then ->
|
67
|
+
expect($body.css('overflow-y')).toEqual('scroll')
|
68
|
+
expect(parseInt($body.css('padding-right'))).toBe(0)
|
69
|
+
done()
|
70
|
+
|
71
|
+
it "gives the scrollbar to .up-modal instead of .up-modal-viewport while animating, so we don't see scaled scrollbars in a zoom-in animation", (done) ->
|
72
|
+
openPromise = up.modal.extract('.container', '<div class="container">text</div>', animation: 'fade-in', duration: 100)
|
56
73
|
$modal = $('.up-modal')
|
57
74
|
$viewport = $modal.find('.up-modal-viewport')
|
58
|
-
$
|
59
|
-
expect($
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
expect($
|
75
|
+
expect($modal.css('overflow-y')).toEqual('scroll')
|
76
|
+
expect($viewport.css('overflow-y')).toEqual('hidden')
|
77
|
+
openPromise.then ->
|
78
|
+
expect($modal.css('overflow-y')).toEqual('auto')
|
79
|
+
expect($viewport.css('overflow-y')).toEqual('scroll')
|
80
|
+
closePromise = up.modal.close(animation: 'fade-out', duration: 100)
|
81
|
+
expect($modal.css('overflow-y')).toEqual('scroll')
|
82
|
+
expect($viewport.css('overflow-y')).toEqual('hidden')
|
83
|
+
done()
|
84
|
+
|
85
|
+
|
86
|
+
it 'does not add right padding to the body if the body has overflow-y: hidden', (done) ->
|
87
|
+
restoreBody = u.temporaryCss($('body'), 'overflow-y': 'hidden')
|
88
|
+
|
89
|
+
up.modal.extract('.container', '<div class="container">text</div>').then ->
|
90
|
+
$body = $('body')
|
91
|
+
expect($('.up-modal')).toExist()
|
66
92
|
expect(parseInt($body.css('padding-right'))).toBe(0)
|
67
93
|
|
68
|
-
|
94
|
+
up.modal.close().then ->
|
95
|
+
expect(parseInt($body.css('padding-right'))).toBe(0)
|
96
|
+
restoreBody()
|
97
|
+
done()
|
69
98
|
|
70
|
-
|
99
|
+
it 'does not add right padding to the body if the body has overflow-y: auto, but does not currently have scrollbars', (done) ->
|
100
|
+
restoreBody = u.temporaryCss($('body'), 'overflow-y': 'auto')
|
101
|
+
restoreReporter = u.temporaryCss($('.jasmine_html-reporter'), 'height': '100px', 'overflow-y': 'hidden')
|
71
102
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
103
|
+
up.modal.extract('.container', '<div class="container">text</div>').then ->
|
104
|
+
$body = $('body')
|
105
|
+
expect($('.up-modal')).toExist()
|
106
|
+
expect(parseInt($body.css('padding-right'))).toBe(0)
|
76
107
|
|
77
|
-
|
108
|
+
up.modal.close().then ->
|
109
|
+
expect(parseInt($body.css('padding-right'))).toBe(0)
|
110
|
+
restoreReporter()
|
111
|
+
restoreBody()
|
112
|
+
done()
|
78
113
|
|
79
|
-
|
114
|
+
it 'pushes right-anchored elements away from the edge of the screen', (done) ->
|
80
115
|
|
81
|
-
|
82
|
-
|
116
|
+
$anchoredElement = affix('div[up-anchored=right]').css
|
117
|
+
position: 'absolute'
|
118
|
+
top: '0'
|
119
|
+
right: '30px'
|
120
|
+
|
121
|
+
promise = up.modal.visit('/foo', target: '.container')
|
122
|
+
|
123
|
+
@respondWith('<div class="container">text</div>')
|
124
|
+
|
125
|
+
promise.then ->
|
126
|
+
expect(parseInt($anchoredElement.css('right'))).toBeAround(30 + assumedScrollbarWidth, 10)
|
127
|
+
|
128
|
+
up.modal.close().then ->
|
129
|
+
expect(parseInt($anchoredElement.css('right'))).toBeAround(30 , 10)
|
130
|
+
done()
|
131
|
+
|
132
|
+
describe 'opening a modal while another modal is open', ->
|
133
|
+
|
134
|
+
it 'does not open multiple modals or pad the body twice if the user starts loading a second modal before the first was done loading', (done) ->
|
135
|
+
up.modal.config.closeDuration = 10
|
136
|
+
promise1 = up.modal.visit('/path1', target: '.container', animation: 'fade-in', duration: 100)
|
137
|
+
promise2 = up.modal.visit('/path2', target: '.container', animation: 'fade-in', duration: 100)
|
138
|
+
expect(jasmine.Ajax.requests.count()).toBe(2)
|
139
|
+
request1 = jasmine.Ajax.requests.at(0)
|
140
|
+
request2 = jasmine.Ajax.requests.at(1)
|
141
|
+
|
142
|
+
u.setTimer 10, =>
|
143
|
+
@respondWith('<div class="container">response1</div>', request: request1)
|
144
|
+
u.setTimer 10, =>
|
145
|
+
@respondWith('<div class="container">response2</div>', request: request2)
|
146
|
+
u.setTimer 50, =>
|
147
|
+
expect($('.up-modal').length).toBe(1)
|
148
|
+
expect($('.up-modal-dialog').length).toBe(1)
|
149
|
+
expect($('.container')).toHaveText('response2')
|
150
|
+
bodyPadding = parseInt($('body').css('padding-right'))
|
151
|
+
expect(bodyPadding).toBeAround(assumedScrollbarWidth, 10)
|
152
|
+
expect(bodyPadding).not.toBeAround(2 * assumedScrollbarWidth, 2 * 5)
|
153
|
+
done()
|
154
|
+
|
155
|
+
it 'closes the current modal and wait for its close animation to finish before starting the open animation of a second modal', (done) ->
|
156
|
+
up.modal.config.openAnimation = 'fade-in'
|
157
|
+
up.modal.config.openDuration = 5
|
158
|
+
up.modal.config.closeAnimation = 'fade-out'
|
159
|
+
up.modal.config.closeDuration = 50
|
160
|
+
|
161
|
+
events = []
|
162
|
+
u.each ['up:modal:open', 'up:modal:opened', 'up:modal:close', 'up:modal:closed'], (event) ->
|
163
|
+
up.on event, ->
|
164
|
+
events.push(event)
|
165
|
+
|
166
|
+
up.modal.extract('.target', '<div class="target">response1</div>')
|
167
|
+
|
168
|
+
# First modal is starting opening animation
|
169
|
+
expect(events).toEqual ['up:modal:open']
|
170
|
+
expect($('.target')).toHaveText('response1')
|
171
|
+
|
172
|
+
u.setTimer 40, ->
|
173
|
+
# First modal has completed opening animation
|
174
|
+
expect(events).toEqual ['up:modal:open', 'up:modal:opened']
|
175
|
+
expect($('.target')).toHaveText('response1')
|
176
|
+
|
177
|
+
up.modal.extract('.target', '<div class="target">response2</div>')
|
178
|
+
|
179
|
+
# First modal is starting close animation. Second modal waits for that.
|
180
|
+
expect(events).toEqual ['up:modal:open', 'up:modal:opened', 'up:modal:open', 'up:modal:close']
|
181
|
+
expect($('.target')).toHaveText('response1')
|
182
|
+
|
183
|
+
u.setTimer 40, ->
|
184
|
+
|
185
|
+
# Second modal is still waiting for first modal's closing animaton to finish.
|
186
|
+
expect(events).toEqual ['up:modal:open', 'up:modal:opened', 'up:modal:open', 'up:modal:close']
|
187
|
+
expect($('.target')).toHaveText('response1')
|
188
|
+
|
189
|
+
u.setTimer 100, ->
|
190
|
+
|
191
|
+
# First modal has finished closing, second modal has finished opening.
|
192
|
+
expect(events).toEqual ['up:modal:open', 'up:modal:opened', 'up:modal:open', 'up:modal:close', 'up:modal:closed', 'up:modal:opened']
|
193
|
+
expect($('.target')).toHaveText('response2')
|
194
|
+
|
195
|
+
done()
|
196
|
+
|
197
|
+
it 'closes an opening modal if a second modal starts opening before the first modal has finished its open animation', (done) ->
|
198
|
+
up.modal.config.openAnimation = 'fade-in'
|
199
|
+
up.modal.config.openDuration = 50
|
200
|
+
up.modal.config.closeAnimation = 'fade-out'
|
201
|
+
up.modal.config.closeDuration = 50
|
202
|
+
|
203
|
+
up.modal.extract('.target', '<div class="target">response1</div>')
|
204
|
+
|
205
|
+
u.setTimer 10, ->
|
206
|
+
# First modal is still in its opening animation
|
207
|
+
expect($('.target')).toHaveText('response1')
|
208
|
+
|
209
|
+
up.modal.extract('.target', '<div class="target">response2</div>')
|
210
|
+
|
211
|
+
# First modal is starting close animation. Second modal waits for that.
|
212
|
+
expect($('.target')).toHaveText('response1')
|
213
|
+
|
214
|
+
u.setTimer 10, ->
|
215
|
+
# Second modal is still waiting for first modal's closing animaton to finish.
|
216
|
+
expect($('.target')).toHaveText('response1')
|
217
|
+
|
218
|
+
u.setTimer 90, ->
|
219
|
+
# First modal has finished closing, second modal has finished opening.
|
220
|
+
expect($('.target')).toHaveText('response2')
|
221
|
+
|
222
|
+
done()
|
223
|
+
|
224
|
+
it 'uses the correct flavor config for the first and second modal', (done) ->
|
225
|
+
up.modal.config.openAnimation = 'fade-in'
|
226
|
+
up.modal.config.openDuration = 10
|
227
|
+
up.modal.config.closeAnimation = 'fade-out'
|
228
|
+
up.modal.config.closeDuration = 10
|
229
|
+
up.modal.flavor 'drawer',
|
230
|
+
openAnimation: 'move-from-right'
|
231
|
+
closeAnimation: 'move-to-right'
|
232
|
+
|
233
|
+
animations = []
|
234
|
+
spyOn(up, 'animate').and.callFake ($element, animation, options) ->
|
235
|
+
if $element.is('.up-modal-viewport')
|
236
|
+
animations.push
|
237
|
+
text: u.trim($element.find('.target').text())
|
238
|
+
animation: animation
|
239
|
+
deferred = $.Deferred()
|
240
|
+
u.setTimer options.duration, -> deferred.resolve()
|
241
|
+
deferred.promise()
|
242
|
+
|
243
|
+
up.modal.extract('.target', '<div class="target">response1</div>')
|
244
|
+
expect(animations).toEqual [
|
245
|
+
{ animation: 'fade-in', text: 'response1' }
|
246
|
+
]
|
247
|
+
|
248
|
+
up.modal.extract('.target', '<div class="target">response2</div>', flavor: 'drawer')
|
249
|
+
|
250
|
+
expect(animations).toEqual [
|
251
|
+
{ animation: 'fade-in', text: 'response1' },
|
252
|
+
{ animation: 'fade-out', text: 'response1' }
|
253
|
+
]
|
254
|
+
|
255
|
+
u.setTimer 20, ->
|
256
|
+
|
257
|
+
expect(animations).toEqual [
|
258
|
+
{ animation: 'fade-in', text: 'response1' },
|
259
|
+
{ animation: 'fade-out', text: 'response1' },
|
260
|
+
{ animation: 'move-from-right', text: 'response2' }
|
261
|
+
]
|
262
|
+
|
263
|
+
expect($('.up-modal').attr('up-flavor')).toEqual('drawer')
|
83
264
|
|
84
|
-
up.modal.close().then ->
|
85
|
-
expect(parseInt($anchoredElement.css('right'))).toBeAround(30 , 10)
|
86
265
|
done()
|
87
266
|
|
88
|
-
|
89
|
-
up.modal.
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
267
|
+
|
268
|
+
it 'does not explode if up.modal.close() was called before the response was received', ->
|
269
|
+
up.modal.visit('/foo', target: '.container')
|
270
|
+
up.modal.close()
|
271
|
+
respond = => @respondWith('<div class="container">text</div>')
|
272
|
+
expect(respond).not.toThrowError()
|
273
|
+
expect($('.up-error')).not.toExist()
|
94
274
|
|
95
275
|
describe 'up.modal.coveredUrl', ->
|
96
276
|
|
@@ -107,6 +287,28 @@ describe 'up.modal', ->
|
|
107
287
|
expect(up.modal.coveredUrl()).toBeUndefined()
|
108
288
|
done()
|
109
289
|
|
290
|
+
describe 'up.modal.flavor', ->
|
291
|
+
|
292
|
+
it 'registers a new modal variant with its own default configuration', ->
|
293
|
+
up.modal.flavor('variant', { maxWidth: 200 })
|
294
|
+
$link = affix('a[href="/path"][up-modal=".target"][up-flavor="variant"]')
|
295
|
+
Trigger.click($link)
|
296
|
+
@respondWith('<div class="target">new text</div>')
|
297
|
+
$modal = $('.up-modal')
|
298
|
+
$dialog = $modal.find('.up-modal-dialog')
|
299
|
+
expect($modal).toBeInDOM()
|
300
|
+
expect($modal.attr('up-flavor')).toEqual('variant')
|
301
|
+
expect($dialog.attr('style')).toContain('max-width: 200px')
|
302
|
+
|
303
|
+
it 'does not change the configuration of non-flavored modals', ->
|
304
|
+
up.modal.flavor('variant', { maxWidth: 200 })
|
305
|
+
$link = affix('a[href="/path"][up-modal=".target"]')
|
306
|
+
Trigger.click($link)
|
307
|
+
@respondWith('<div class="target">new text</div>')
|
308
|
+
$modal = $('.up-modal')
|
309
|
+
$dialog = $modal.find('.up-modal-dialog')
|
310
|
+
expect($modal).toBeInDOM()
|
311
|
+
expect($dialog.attr('style')).toBeBlank()
|
110
312
|
|
111
313
|
describe 'up.modal.close', ->
|
112
314
|
|
@@ -10,17 +10,29 @@ describe 'up.motion', ->
|
|
10
10
|
|
11
11
|
it 'animates the given element', (done) ->
|
12
12
|
$element = affix('.element').text('content')
|
13
|
-
opacity = -> Number($element.css('opacity'))
|
14
13
|
up.animate($element, 'fade-in', duration: 200, easing: 'linear')
|
15
14
|
|
16
15
|
u.setTimer 0, ->
|
17
|
-
expect(opacity()).toBeAround(0.0, 0.25)
|
16
|
+
expect(u.opacity($element)).toBeAround(0.0, 0.25)
|
18
17
|
u.setTimer 100, ->
|
19
|
-
expect(opacity()).toBeAround(0.5, 0.25)
|
18
|
+
expect(u.opacity($element)).toBeAround(0.5, 0.25)
|
20
19
|
u.setTimer 200, ->
|
21
|
-
expect(opacity()).toBeAround(1.0, 0.25)
|
20
|
+
expect(u.opacity($element)).toBeAround(1.0, 0.25)
|
22
21
|
done()
|
23
22
|
|
23
|
+
it 'returns a promise that is resolved when the animation completed', (done) ->
|
24
|
+
$element = affix('.element').text('content')
|
25
|
+
resolveSpy = jasmine.createSpy('resolve')
|
26
|
+
|
27
|
+
promise = up.animate($element, 'fade-in', duration: 100, easing: 'linear')
|
28
|
+
promise.then(resolveSpy)
|
29
|
+
|
30
|
+
u.setTimer 50, ->
|
31
|
+
expect(resolveSpy).not.toHaveBeenCalled()
|
32
|
+
u.setTimer 70, ->
|
33
|
+
expect(resolveSpy).toHaveBeenCalled()
|
34
|
+
done()
|
35
|
+
|
24
36
|
it 'cancels an existing animation on the element by instantly jumping to the last frame', ->
|
25
37
|
$element = affix('.element').text('content')
|
26
38
|
up.animate($element, { 'font-size': '40px' }, duration: 10000, easing: 'linear')
|
@@ -74,17 +86,15 @@ describe 'up.motion', ->
|
|
74
86
|
it 'restores existing transitions on the element', ->
|
75
87
|
$element = affix('.element').text('content')
|
76
88
|
$element.css('transition': 'font-size 3s ease')
|
77
|
-
|
78
|
-
expect(
|
89
|
+
oldTransitionProperty = $element.css('transition-property')
|
90
|
+
expect(oldTransitionProperty).toContain('font-size') # be paranoid
|
79
91
|
up.animate($element, 'fade-in', duration: 10000)
|
80
92
|
up.motion.finish($element)
|
81
|
-
expect(
|
82
|
-
|
83
|
-
expect(
|
84
|
-
expect(
|
85
|
-
expect(
|
86
|
-
expect(currentTransition).not.toContain('none')
|
87
|
-
expect(currentTransition).not.toContain('all')
|
93
|
+
expect(u.opacity($element)).toEqual(1)
|
94
|
+
currentTransitionProperty = $element.css('transition-property')
|
95
|
+
expect(currentTransitionProperty).toEqual(oldTransitionProperty)
|
96
|
+
expect(currentTransitionProperty).toContain('font-size')
|
97
|
+
expect(currentTransitionProperty).not.toContain('opacity')
|
88
98
|
|
89
99
|
it 'cancels an existing transition on the element by instantly jumping to the last frame', ->
|
90
100
|
$old = affix('.old').text('old content')
|
@@ -136,17 +146,15 @@ describe 'up.motion', ->
|
|
136
146
|
up.animate($element1, 'fade-in', duration: 3000)
|
137
147
|
up.animate($element2, 'fade-in', duration: 3000)
|
138
148
|
|
139
|
-
opacity
|
140
|
-
|
141
|
-
expect(opacity($element1)).toBeAround(0.0, 0.1)
|
142
|
-
expect(opacity($element2)).toBeAround(0.0, 0.1)
|
149
|
+
expect(u.opacity($element1)).toBeAround(0.0, 0.1)
|
150
|
+
expect(u.opacity($element2)).toBeAround(0.0, 0.1)
|
143
151
|
|
144
152
|
up.motion.finish()
|
145
153
|
|
146
154
|
$element1 = $('.element1')
|
147
155
|
$element2 = $('.element2')
|
148
|
-
expect(opacity($element1)).toBe(1.0)
|
149
|
-
expect(opacity($element2)).toBe(1.0)
|
156
|
+
expect(u.opacity($element1)).toBe(1.0)
|
157
|
+
expect(u.opacity($element2)).toBe(1.0)
|
150
158
|
|
151
159
|
describe 'up.morph', ->
|
152
160
|
|
@@ -222,19 +230,17 @@ describe 'up.motion', ->
|
|
222
230
|
height: '23px'
|
223
231
|
)
|
224
232
|
|
225
|
-
opacity = ($element) -> Number($element.css('opacity'))
|
226
|
-
|
227
233
|
u.setTimer 0, ->
|
228
|
-
expect(opacity($newGhost)).toBeAround(0.0, 0.25)
|
229
|
-
expect(opacity($oldGhost)).toBeAround(1.0, 0.25)
|
234
|
+
expect(u.opacity($newGhost)).toBeAround(0.0, 0.25)
|
235
|
+
expect(u.opacity($oldGhost)).toBeAround(1.0, 0.25)
|
230
236
|
|
231
237
|
u.setTimer 80, ->
|
232
|
-
expect(opacity($newGhost)).toBeAround(0.4, 0.25)
|
233
|
-
expect(opacity($oldGhost)).toBeAround(0.6, 0.25)
|
238
|
+
expect(u.opacity($newGhost)).toBeAround(0.4, 0.25)
|
239
|
+
expect(u.opacity($oldGhost)).toBeAround(0.6, 0.25)
|
234
240
|
|
235
241
|
u.setTimer 140, ->
|
236
|
-
expect(opacity($newGhost)).toBeAround(0.7, 0.25)
|
237
|
-
expect(opacity($oldGhost)).toBeAround(0.3, 0.25)
|
242
|
+
expect(u.opacity($newGhost)).toBeAround(0.7, 0.25)
|
243
|
+
expect(u.opacity($oldGhost)).toBeAround(0.3, 0.25)
|
238
244
|
|
239
245
|
u.setTimer 250, ->
|
240
246
|
# Once our two ghosts have rendered their visual effect,
|
@@ -43,6 +43,78 @@ describe 'up.popup', ->
|
|
43
43
|
expect(respond).not.toThrowError()
|
44
44
|
expect($('.up-error')).not.toExist()
|
45
45
|
|
46
|
+
describe 'with { html } option', ->
|
47
|
+
|
48
|
+
it 'extracts the selector from the given HTML string', ->
|
49
|
+
$span = affix('span')
|
50
|
+
up.popup.attach($span, target: '.container', html: "<div class='container'>container contents</div>")
|
51
|
+
expect($('.up-popup')).toHaveText('container contents')
|
52
|
+
|
53
|
+
describe 'opening a popup while another modal is open', ->
|
54
|
+
|
55
|
+
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) ->
|
56
|
+
$span = affix('span')
|
57
|
+
up.popup.config.closeDuration = 10
|
58
|
+
promise1 = up.popup.attach($span, url: '/path1', target: '.container', animation: 'fade-in', duration: 100)
|
59
|
+
promise2 = up.popup.attach($span, url: '/path2', target: '.container', animation: 'fade-in', duration: 100)
|
60
|
+
expect(jasmine.Ajax.requests.count()).toBe(2)
|
61
|
+
request1 = jasmine.Ajax.requests.at(0)
|
62
|
+
request2 = jasmine.Ajax.requests.at(1)
|
63
|
+
|
64
|
+
u.setTimer 10, =>
|
65
|
+
@respondWith('<div class="container">response1</div>', request: request1)
|
66
|
+
u.setTimer 10, =>
|
67
|
+
@respondWith('<div class="container">response2</div>', request: request2)
|
68
|
+
u.setTimer 30, =>
|
69
|
+
expect($('.up-popup').length).toBe(1)
|
70
|
+
expect($('.container')).toHaveText('response2')
|
71
|
+
done()
|
72
|
+
|
73
|
+
it 'closes the current popup and wait for its close animation to finish before starting the open animation of a second popup', (done) ->
|
74
|
+
$span = affix('span')
|
75
|
+
up.popup.config.openAnimation = 'fade-in'
|
76
|
+
up.popup.config.openDuration = 5
|
77
|
+
up.popup.config.closeAnimation = 'fade-out'
|
78
|
+
up.popup.config.closeDuration = 50
|
79
|
+
|
80
|
+
events = []
|
81
|
+
u.each ['up:popup:open', 'up:popup:opened', 'up:popup:close', 'up:popup:closed'], (event) ->
|
82
|
+
up.on event, ->
|
83
|
+
events.push(event)
|
84
|
+
|
85
|
+
up.popup.attach($span, { target: '.target', html: '<div class="target">response1</div>' })
|
86
|
+
|
87
|
+
# First popup is starting opening animation
|
88
|
+
expect(events).toEqual ['up:popup:open']
|
89
|
+
expect($('.target')).toHaveText('response1')
|
90
|
+
|
91
|
+
u.setTimer 30, ->
|
92
|
+
# First popup has completed opening animation
|
93
|
+
expect(events).toEqual ['up:popup:open', 'up:popup:opened']
|
94
|
+
expect($('.target')).toHaveText('response1')
|
95
|
+
|
96
|
+
up.popup.attach($span, { target: '.target', html: '<div class="target">response2</div>' })
|
97
|
+
|
98
|
+
# First popup is starting close animation. Second popup waits for that.
|
99
|
+
expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:open', 'up:popup:close']
|
100
|
+
expect($('.target')).toHaveText('response1')
|
101
|
+
|
102
|
+
u.setTimer 15, ->
|
103
|
+
|
104
|
+
# Second popup is still waiting for first popup's closing animaton to finish.
|
105
|
+
expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:open', 'up:popup:close']
|
106
|
+
expect($('.target')).toHaveText('response1')
|
107
|
+
|
108
|
+
u.setTimer 100, ->
|
109
|
+
|
110
|
+
# First popup has finished closing, second popup has finished opening.
|
111
|
+
expect(events).toEqual ['up:popup:open', 'up:popup:opened', 'up:popup:open', 'up:popup:close', 'up:popup:closed', 'up:popup:opened']
|
112
|
+
expect($('.target')).toHaveText('response2')
|
113
|
+
|
114
|
+
done()
|
115
|
+
|
116
|
+
|
117
|
+
|
46
118
|
describe 'up.popup.coveredUrl', ->
|
47
119
|
|
48
120
|
describeCapability 'canPushState', ->
|
@@ -15,15 +15,28 @@ describe 'up.syntax', ->
|
|
15
15
|
expect(observeClass).not.toHaveBeenCalledWith('container')
|
16
16
|
expect(observeClass).toHaveBeenCalledWith('child')
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
describe 'destructors', ->
|
19
|
+
|
20
|
+
it 'allows initializers to return a function that is called when the compiled element is removed', ->
|
21
|
+
destructor = jasmine.createSpy('destructor')
|
22
|
+
up.compiler '.child', ($element) ->
|
23
|
+
destructor
|
24
|
+
|
25
|
+
up.hello(affix('.container .child'))
|
26
|
+
expect(destructor).not.toHaveBeenCalled()
|
27
|
+
|
28
|
+
up.destroy('.container')
|
29
|
+
expect(destructor).toHaveBeenCalled()
|
30
|
+
|
31
|
+
it 'does not throw an error if both container and child have a destructor, and the container gets destroyed', ->
|
32
|
+
up.compiler '.container', ($element) ->
|
33
|
+
return (->)
|
34
|
+
|
35
|
+
up.compiler '.child', ($element) ->
|
36
|
+
return (->)
|
37
|
+
|
38
|
+
destruction = -> up.destroy('.container')
|
39
|
+
expect(destruction).not.toThrowError()
|
27
40
|
|
28
41
|
it 'parses an up-data attribute as JSON and passes the parsed object as a second argument to the initializer', ->
|
29
42
|
|
@@ -101,7 +114,7 @@ describe 'up.syntax', ->
|
|
101
114
|
up.compiler '.element', { priority: 3 }, -> traces.push('bam')
|
102
115
|
up.compiler '.element', { priority: -1 }, -> traces.push('qux')
|
103
116
|
up.hello(affix('.element'))
|
104
|
-
expect(traces).toEqual ['
|
117
|
+
expect(traces).toEqual ['bam', 'bar', 'foo', 'baz', 'qux']
|
105
118
|
|
106
119
|
it 'considers priority-less compilers to be priority zero', ->
|
107
120
|
traces = []
|
@@ -109,7 +122,7 @@ describe 'up.syntax', ->
|
|
109
122
|
up.compiler '.element', -> traces.push('bar')
|
110
123
|
up.compiler '.element', { priority: -1 }, -> traces.push('baz')
|
111
124
|
up.hello(affix('.element'))
|
112
|
-
expect(traces).toEqual ['
|
125
|
+
expect(traces).toEqual ['foo', 'bar', 'baz']
|
113
126
|
|
114
127
|
it 'runs two compilers with the same priority in the order in which they were registered', ->
|
115
128
|
traces = []
|
@@ -126,7 +139,7 @@ describe 'up.syntax', ->
|
|
126
139
|
up.compiler '.element', { priority: -1000 }, -> traces.push('bar')
|
127
140
|
up.macro '.element', -> traces.push('baz')
|
128
141
|
up.hello(affix('.element'))
|
129
|
-
expect(traces).toEqual ['baz', '
|
142
|
+
expect(traces).toEqual ['baz', 'foo' , 'bar']
|
130
143
|
|
131
144
|
it 'allows to macros to have priorities of their own', ->
|
132
145
|
traces = []
|
@@ -135,8 +148,33 @@ describe 'up.syntax', ->
|
|
135
148
|
up.macro '.element', { priority: 0 }, -> traces.push('baz')
|
136
149
|
up.macro '.element', { priority: 3 }, -> traces.push('bam')
|
137
150
|
up.macro '.element', { priority: -1 }, -> traces.push('qux')
|
151
|
+
up.compiler '.element', { priority: 999 }, -> traces.push('ccc')
|
152
|
+
up.hello(affix('.element'))
|
153
|
+
expect(traces).toEqual ['bam', 'bar', 'foo', 'baz', 'qux', 'ccc']
|
154
|
+
|
155
|
+
it 'runs two macros with the same priority in the order in which they were registered', ->
|
156
|
+
traces = []
|
157
|
+
up.macro '.element', { priority: 1 }, -> traces.push('foo')
|
158
|
+
up.macro '.element', { priority: 1 }, -> traces.push('bar')
|
138
159
|
up.hello(affix('.element'))
|
139
|
-
expect(traces).toEqual ['
|
160
|
+
expect(traces).toEqual ['foo', 'bar']
|
161
|
+
|
162
|
+
it 'allows users to use the built-in [up-expand] from their own macros', ->
|
163
|
+
up.macro '.element', ($element) ->
|
164
|
+
$element.attr('up-expand', '')
|
165
|
+
$element = affix('.element a[href="/foo"][up-target=".target"]')
|
166
|
+
up.hello($element)
|
167
|
+
expect($element.attr('up-target')).toEqual('.target')
|
168
|
+
expect($element.attr('up-href')).toEqual('/foo')
|
169
|
+
|
170
|
+
it 'allows users to use the built-in [up-dash] from their own macros', ->
|
171
|
+
up.macro '.element', ($element) ->
|
172
|
+
$element.attr('up-dash', '.target')
|
173
|
+
$element = affix('a.element[href="/foo"]')
|
174
|
+
up.hello($element)
|
175
|
+
expect($element.attr('up-target')).toEqual('.target')
|
176
|
+
expect($element.attr('up-preload')).toEqual('')
|
177
|
+
expect($element.attr('up-instant')).toEqual('')
|
140
178
|
|
141
179
|
describe 'up.hello', ->
|
142
180
|
|
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.25.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-04-
|
11
|
+
date: 2016-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|