unpoly-rails 0.24.1 → 0.25.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.
- 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
|