unpoly-rails 0.26.2 → 0.27.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 +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
|