upjs-rails 0.15.1 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/dist/up.js +219 -110
- data/dist/up.min.js +2 -2
- data/lib/assets/javascripts/up/flow.js.coffee +22 -17
- data/lib/assets/javascripts/up/form.js.coffee +1 -1
- data/lib/assets/javascripts/up/modal.js.coffee +19 -14
- data/lib/assets/javascripts/up/motion.js.coffee +31 -2
- data/lib/assets/javascripts/up/popup.js.coffee +31 -20
- data/lib/assets/javascripts/up/proxy.js.coffee +47 -8
- data/lib/assets/javascripts/up/syntax.js.coffee +4 -2
- data/lib/assets/javascripts/up/tooltip.js.coffee +1 -1
- data/lib/assets/javascripts/up/util.js.coffee +27 -31
- data/lib/upjs/rails/version.rb +1 -1
- data/spec_app/Gemfile.lock +4 -1
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +57 -1
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +25 -0
- data/spec_app/spec/javascripts/up/popup_spec.js.coffee +77 -6
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +21 -1
- metadata +2 -2
@@ -304,13 +304,15 @@ up.syntax = (($) ->
|
|
304
304
|
|
305
305
|
@function up.hello
|
306
306
|
@param {String|Element|jQuery} selectorOrElement
|
307
|
+
@param {String|Element|jQuery} [options.origin]
|
307
308
|
@return {jQuery}
|
308
309
|
The compiled element
|
309
310
|
@stable
|
310
311
|
###
|
311
|
-
hello = (selectorOrElement) ->
|
312
|
+
hello = (selectorOrElement, options) ->
|
312
313
|
$element = $(selectorOrElement)
|
313
|
-
|
314
|
+
eventAttrs = u.options(options, $element: $element)
|
315
|
+
up.emit('up:fragment:inserted', eventAttrs)
|
314
316
|
$element
|
315
317
|
|
316
318
|
###*
|
@@ -149,7 +149,7 @@ up.tooltip = (($) ->
|
|
149
149
|
###*
|
150
150
|
Displays a tooltip with HTML content when hovering the mouse over this element:
|
151
151
|
|
152
|
-
<a href="/decks" up-tooltip="Show <b>all</b> decks">Decks</a>
|
152
|
+
<a href="/decks" up-tooltip-html="Show <b>all</b> decks">Decks</a>
|
153
153
|
|
154
154
|
@selector [up-tooltip-html]
|
155
155
|
@stable
|
@@ -913,37 +913,33 @@ up.util = (($) ->
|
|
913
913
|
###
|
914
914
|
cssAnimate = (elementOrSelector, lastFrame, opts) ->
|
915
915
|
$element = $(elementOrSelector)
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
transition
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
else
|
944
|
-
$element.css(lastFrame)
|
945
|
-
resolvedDeferred()
|
946
|
-
|
916
|
+
opts = options(opts,
|
917
|
+
duration: 300,
|
918
|
+
delay: 0,
|
919
|
+
easing: 'ease'
|
920
|
+
)
|
921
|
+
# We don't finish an existing animation here, since
|
922
|
+
# the public API `up.motion.animate` already does this.
|
923
|
+
deferred = $.Deferred()
|
924
|
+
transition =
|
925
|
+
'transition-property': Object.keys(lastFrame).join(', ')
|
926
|
+
'transition-duration': "#{opts.duration}ms"
|
927
|
+
'transition-delay': "#{opts.delay}ms"
|
928
|
+
'transition-timing-function': opts.easing
|
929
|
+
withoutCompositing = forceCompositing($element)
|
930
|
+
withoutTransition = temporaryCss($element, transition)
|
931
|
+
$element.css(lastFrame)
|
932
|
+
deferred.then(withoutCompositing)
|
933
|
+
deferred.then(withoutTransition)
|
934
|
+
$element.data(ANIMATION_PROMISE_KEY, deferred)
|
935
|
+
deferred.then(-> $element.removeData(ANIMATION_PROMISE_KEY))
|
936
|
+
endTimeout = setTimeout((-> deferred.resolve()), opts.duration + opts.delay)
|
937
|
+
deferred.then(-> clearTimeout(endTimeout)) # clean up in case we're canceled
|
938
|
+
# Return the whole deferred and not just return a thenable.
|
939
|
+
# Other code will need the possibility to cancel the animation
|
940
|
+
# by resolving the deferred.
|
941
|
+
deferred
|
942
|
+
|
947
943
|
ANIMATION_PROMISE_KEY = 'up-animation-promise'
|
948
944
|
|
949
945
|
###*
|
data/lib/upjs/rails/version.rb
CHANGED
data/spec_app/Gemfile.lock
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
describe 'up.modal', ->
|
2
|
+
|
3
|
+
u = up.util
|
2
4
|
|
3
5
|
describe 'Javascript functions', ->
|
4
6
|
|
@@ -64,6 +66,12 @@ describe 'up.modal', ->
|
|
64
66
|
expect(parseInt($anchoredElement.css('right'))).toBeAround(30 , 10)
|
65
67
|
done()
|
66
68
|
|
69
|
+
it 'does not explode if the modal was closed before the response was received', ->
|
70
|
+
up.modal.visit('/foo', target: '.container')
|
71
|
+
up.modal.close()
|
72
|
+
respond = => @respondWith('<div class="container">text</div>')
|
73
|
+
expect(respond).not.toThrowError()
|
74
|
+
expect($('.up-error')).not.toExist()
|
67
75
|
|
68
76
|
describe 'up.modal.coveredUrl', ->
|
69
77
|
|
@@ -134,16 +142,64 @@ describe 'up.modal', ->
|
|
134
142
|
expect(wasClosed).toBe(false)
|
135
143
|
expect(wasDefaultPrevented).toBe(false)
|
136
144
|
|
137
|
-
describe 'when
|
145
|
+
describe 'when replacing content', ->
|
146
|
+
|
147
|
+
beforeEach ->
|
148
|
+
up.motion.config.enabled = false
|
138
149
|
|
139
150
|
it 'prefers to replace a selector within the modal', ->
|
140
151
|
$outside = affix('.foo').text('old outside')
|
141
152
|
up.modal.visit('/path', target: '.foo')
|
142
153
|
@respondWith("<div class='foo'>old inside</div>")
|
143
154
|
up.flow.implant('.foo', "<div class='foo'>new text</div>")
|
155
|
+
expect($outside).toBeInDOM()
|
144
156
|
expect($outside).toHaveText('old outside')
|
145
157
|
expect($('.up-modal-content')).toHaveText('new text')
|
146
158
|
|
159
|
+
it 'auto-closes the modal when a replacement from inside the modal affects a selector behind the modal', ->
|
160
|
+
affix('.outside').text('old outside')
|
161
|
+
up.modal.visit('/path', target: '.inside')
|
162
|
+
@respondWith("<div class='inside'>old inside</div>")
|
163
|
+
up.flow.implant('.outside', "<div class='outside'>new outside</div>", origin: $('.inside'))
|
164
|
+
expect($('.outside')).toHaveText('new outside')
|
165
|
+
expect($('.up-modal')).not.toExist()
|
166
|
+
|
167
|
+
it 'does not auto-close the modal when a replacement from inside the modal affects a selector inside the modal', ->
|
168
|
+
affix('.outside').text('old outside')
|
169
|
+
up.modal.visit('/path', target: '.inside')
|
170
|
+
@respondWith("<div class='inside'>old inside</div>")
|
171
|
+
up.flow.implant('.inside', "<div class='inside'>new inside</div>", origin: $('.inside'))
|
172
|
+
expect($('.inside')).toHaveText('new inside')
|
173
|
+
expect($('.up-modal')).toExist()
|
174
|
+
|
175
|
+
it 'does not auto-close the modal when a replacement from outside the modal affects a selector outside the modal', ->
|
176
|
+
affix('.outside').text('old outside')
|
177
|
+
up.modal.visit('/path', target: '.inside')
|
178
|
+
@respondWith("<div class='inside'>old inside</div>")
|
179
|
+
up.flow.implant('.outside', "<div class='outside'>new outside</div>", origin: $('.outside'))
|
180
|
+
expect($('.outside')).toHaveText('new outside')
|
181
|
+
expect($('.up-modal')).toExist()
|
182
|
+
|
183
|
+
it 'does not auto-close the modal when a replacement from outside the modal affects a selector inside the modal', ->
|
184
|
+
affix('.outside').text('old outside')
|
185
|
+
up.modal.visit('/path', target: '.inside')
|
186
|
+
@respondWith("<div class='inside'>old inside</div>")
|
187
|
+
up.flow.implant('.inside', "<div class='inside'>new inside</div>", origin: $('.outside'))
|
188
|
+
expect($('.inside')).toHaveText('new inside')
|
189
|
+
expect($('.up-modal')).toExist()
|
190
|
+
|
191
|
+
it 'does not auto-close the modal when the new fragment is within a popup', ->
|
192
|
+
up.modal.visit('/modal', target: '.modal-content')
|
193
|
+
@respondWith("<div class='modal-content'></div>")
|
194
|
+
up.popup.attach('.modal-content', url: '/popup', target: '.popup-content')
|
195
|
+
@respondWith("<div class='popup-content'></div>")
|
196
|
+
expect($('.up-modal')).toExist()
|
197
|
+
expect($('.up-popup')).toExist()
|
198
|
+
|
199
|
+
describe 'when following links inside a modal', ->
|
200
|
+
|
201
|
+
it 'prefers to replace a selector within the modal', ->
|
202
|
+
|
147
203
|
it 'auto-closes the modal if a selector behind the modal gets replaced'
|
148
204
|
|
149
205
|
it "doesn't auto-close the modal if a selector behind the modal if the modal is sticky"
|
@@ -25,6 +25,16 @@ describe 'up.motion', ->
|
|
25
25
|
up.animate($element, { 'fade-in' }, duration: 100, easing: 'linear')
|
26
26
|
expect($element.css('font-size')).toEqual('40px')
|
27
27
|
|
28
|
+
describe 'with animations disabled globally', ->
|
29
|
+
|
30
|
+
beforeEach ->
|
31
|
+
up.motion.config.enabled = false
|
32
|
+
|
33
|
+
it "doesn't animate and directly sets the last frame instead", ->
|
34
|
+
$element = affix('.element').text('content')
|
35
|
+
up.animate($element, { 'font-size': '40px' }, duration: 10000, easing: 'linear')
|
36
|
+
expect($element.css('font-size')).toEqual('40px')
|
37
|
+
|
28
38
|
else
|
29
39
|
|
30
40
|
it "doesn't animate and directly sets the last frame instead", ->
|
@@ -185,6 +195,20 @@ describe 'up.motion', ->
|
|
185
195
|
# was at the scroll position before we revealed $new.
|
186
196
|
expect($oldGhost.offset().top).toEqual(-300)
|
187
197
|
|
198
|
+
|
199
|
+
describe 'with animations disabled globally', ->
|
200
|
+
|
201
|
+
beforeEach ->
|
202
|
+
up.motion.config.enabled = false
|
203
|
+
|
204
|
+
it "doesn't animate and hides the old element instead", ->
|
205
|
+
$old = affix('.old').text('old content')
|
206
|
+
$new = affix('.new').text('new content')
|
207
|
+
up.morph($old, $new, 'cross-fade', duration: 1000)
|
208
|
+
expect($old).toBeHidden()
|
209
|
+
expect($new).toBeVisible()
|
210
|
+
expect($new.css('opacity')).toEqual('1')
|
211
|
+
|
188
212
|
else
|
189
213
|
|
190
214
|
it "doesn't animate and hides the old element instead", ->
|
@@ -193,6 +217,7 @@ describe 'up.motion', ->
|
|
193
217
|
up.morph($old, $new, 'cross-fade', duration: 1000)
|
194
218
|
expect($old).toBeHidden()
|
195
219
|
expect($new).toBeVisible()
|
220
|
+
expect($new.css('opacity')).toEqual('1')
|
196
221
|
|
197
222
|
describe 'up.transition', ->
|
198
223
|
|
@@ -1,10 +1,18 @@
|
|
1
1
|
describe 'up.popup', ->
|
2
2
|
|
3
|
+
u = up.util
|
4
|
+
|
3
5
|
describe 'Javascript functions', ->
|
4
6
|
|
5
7
|
describe 'up.popup.attach', ->
|
6
8
|
|
7
|
-
it '
|
9
|
+
it 'does not explode if the popup was closed before the response was received', ->
|
10
|
+
$span = affix('span')
|
11
|
+
up.popup.attach($span, url: '/foo', target: '.container')
|
12
|
+
up.popup.close()
|
13
|
+
respond = => @respondWith('<div class="container">text</div>')
|
14
|
+
expect(respond).not.toThrowError()
|
15
|
+
expect($('.up-error')).not.toExist()
|
8
16
|
|
9
17
|
describe 'up.popup.coveredUrl', ->
|
10
18
|
|
@@ -34,6 +42,10 @@ describe 'up.popup', ->
|
|
34
42
|
|
35
43
|
it "loads this link's destination in a popup when clicked", ->
|
36
44
|
$link = affix('a[href="/path/to"][up-popup=".middle"]').text('link')
|
45
|
+
$link.css
|
46
|
+
position: 'fixed'
|
47
|
+
left: '100px'
|
48
|
+
top: '50px'
|
37
49
|
$link.click()
|
38
50
|
expect(@lastRequest().url).toMatch /\/path\/to$/
|
39
51
|
@respondWith """
|
@@ -41,10 +53,19 @@ describe 'up.popup', ->
|
|
41
53
|
<div class="middle">new-middle</div>
|
42
54
|
<div class="after">new-after</div>
|
43
55
|
"""
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
expect($
|
56
|
+
|
57
|
+
$popup = $('.up-popup')
|
58
|
+
|
59
|
+
expect($popup).toExist()
|
60
|
+
expect($popup.find('.middle')).toHaveText('new-middle')
|
61
|
+
expect($popup.find('.before')).not.toExist()
|
62
|
+
expect($popup.find('.after')).not.toExist()
|
63
|
+
|
64
|
+
popupDims = u.measure($popup, full: true)
|
65
|
+
linkDims = u.measure($link, full: true)
|
66
|
+
|
67
|
+
expect(popupDims.right).toBeAround(linkDims.right, 1)
|
68
|
+
expect(popupDims.top).toBeAround(linkDims.top + linkDims.height, 1)
|
48
69
|
|
49
70
|
describe '[up-close]', ->
|
50
71
|
|
@@ -80,4 +101,54 @@ describe 'up.popup', ->
|
|
80
101
|
$link.click()
|
81
102
|
expect(wasClosed).toBe(false)
|
82
103
|
expect(wasDefaultPrevented).toBe(false)
|
83
|
-
|
104
|
+
|
105
|
+
describe 'when replacing content', ->
|
106
|
+
|
107
|
+
beforeEach ->
|
108
|
+
up.motion.config.enabled = false
|
109
|
+
|
110
|
+
it 'prefers to replace a selector within the popup', ->
|
111
|
+
$outside = affix('.foo').text('old outside')
|
112
|
+
$link = affix('.link')
|
113
|
+
up.popup.attach($link, href: '/path', target: '.foo')
|
114
|
+
@respondWith("<div class='foo'>old inside</div>")
|
115
|
+
up.flow.implant('.foo', "<div class='foo'>new text</div>")
|
116
|
+
expect($outside).toBeInDOM()
|
117
|
+
expect($outside).toHaveText('old outside')
|
118
|
+
expect($('.up-popup')).toHaveText('new text')
|
119
|
+
|
120
|
+
it 'auto-closes the popup when a replacement from inside the popup affects a selector behind the popup', ->
|
121
|
+
affix('.outside').text('old outside')
|
122
|
+
$link = affix('.link')
|
123
|
+
up.popup.attach($link, href: '/path', target: '.inside')
|
124
|
+
@respondWith("<div class='inside'>old inside</div>")
|
125
|
+
up.flow.implant('.outside', "<div class='outside'>new outside</div>", origin: $('.inside'))
|
126
|
+
expect($('.outside')).toHaveText('new outside')
|
127
|
+
expect($('.up-popup')).not.toExist()
|
128
|
+
|
129
|
+
it 'does not auto-close the popup when a replacement from inside the popup affects a selector inside the popup', ->
|
130
|
+
affix('.outside').text('old outside')
|
131
|
+
$link = affix('.link')
|
132
|
+
up.popup.attach($link, href: '/path', target: '.inside')
|
133
|
+
@respondWith("<div class='inside'>old inside</div>")
|
134
|
+
up.flow.implant('.inside', "<div class='inside'>new inside</div>", origin: $('.inside'))
|
135
|
+
expect($('.inside')).toHaveText('new inside')
|
136
|
+
expect($('.up-popup')).toExist()
|
137
|
+
|
138
|
+
it 'does not auto-close the popup when a replacement from outside the popup affects a selector outside the popup', ->
|
139
|
+
affix('.outside').text('old outside')
|
140
|
+
$link = affix('.link')
|
141
|
+
up.popup.attach($link, href: '/path', target: '.inside')
|
142
|
+
@respondWith("<div class='inside'>old inside</div>")
|
143
|
+
up.flow.implant('.outside', "<div class='outside'>new outside</div>", origin: $('.outside'))
|
144
|
+
expect($('.outside')).toHaveText('new outside')
|
145
|
+
expect($('.up-popup')).toExist()
|
146
|
+
|
147
|
+
it 'does not auto-close the popup when a replacement from outside the popup affects a selector inside the popup', ->
|
148
|
+
affix('.outside').text('old outside')
|
149
|
+
$link = affix('.link')
|
150
|
+
up.popup.attach($link, href: '/path', target: '.inside')
|
151
|
+
@respondWith("<div class='inside'>old inside</div>")
|
152
|
+
up.flow.implant('.inside', "<div class='inside'>new inside</div>", origin: $('.outside'))
|
153
|
+
expect($('.inside')).toHaveText('new inside')
|
154
|
+
expect($('.up-popup')).toExist()
|
@@ -88,7 +88,7 @@ describe 'up.proxy', ->
|
|
88
88
|
u.times 2, -> up.proxy.ajax(url: '/foo', method: method, cache: true)
|
89
89
|
expect(jasmine.Ajax.requests.count()).toEqual(1)
|
90
90
|
|
91
|
-
it 'does not responses with a non-200 status code', ->
|
91
|
+
it 'does not cache responses with a non-200 status code', ->
|
92
92
|
# Send the same request for the same path, 3 minutes apart
|
93
93
|
up.proxy.ajax(url: '/foo')
|
94
94
|
|
@@ -101,6 +101,26 @@ describe 'up.proxy', ->
|
|
101
101
|
|
102
102
|
expect(jasmine.Ajax.requests.count()).toEqual(2)
|
103
103
|
|
104
|
+
describe 'with config.maxRequests set', ->
|
105
|
+
|
106
|
+
beforeEach ->
|
107
|
+
up.proxy.config.maxRequests = 1
|
108
|
+
|
109
|
+
it 'limits the number of concurrent requests', ->
|
110
|
+
responses = []
|
111
|
+
up.proxy.ajax(url: '/foo').then (html) -> responses.push(html)
|
112
|
+
up.proxy.ajax(url: '/bar').then (html) -> responses.push(html)
|
113
|
+
expect(jasmine.Ajax.requests.count()).toEqual(1) # only one request was made
|
114
|
+
@respondWith('first response', request: jasmine.Ajax.requests.at(0))
|
115
|
+
expect(responses).toEqual ['first response']
|
116
|
+
expect(jasmine.Ajax.requests.count()).toEqual(2) # a second request was made
|
117
|
+
@respondWith('second response', request: jasmine.Ajax.requests.at(1))
|
118
|
+
expect(responses).toEqual ['first response', 'second response']
|
119
|
+
|
120
|
+
# it 'considers preloading links for the request limit', ->
|
121
|
+
# up.proxy.ajax(url: '/foo', preload: true)
|
122
|
+
# up.proxy.ajax(url: '/bar')
|
123
|
+
# expect(jasmine.Ajax.requests.count()).toEqual(1)
|
104
124
|
|
105
125
|
describe 'events', ->
|
106
126
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: upjs-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.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-01-
|
11
|
+
date: 2016-01-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|