upjs-rails 0.10.5 → 0.11.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/dist/up-bootstrap.js +2 -1
- data/dist/up-bootstrap.min.js +1 -1
- data/dist/up.js +213 -73
- data/dist/up.min.js +2 -2
- data/lib/assets/javascripts/up/browser.js.coffee +33 -5
- data/lib/assets/javascripts/up/flow.js.coffee +14 -17
- data/lib/assets/javascripts/up/history.js.coffee +0 -1
- data/lib/assets/javascripts/up/layout.js.coffee +34 -5
- data/lib/assets/javascripts/up/modal.js.coffee +26 -8
- data/lib/assets/javascripts/up/motion.js.coffee +74 -30
- data/lib/assets/javascripts/up/popup.js.coffee +5 -1
- data/lib/assets/javascripts/up/proxy.js.coffee +2 -0
- data/lib/assets/javascripts/up/util.js.coffee +47 -6
- data/lib/assets/javascripts/up-bootstrap/layout-ext.js.coffee +1 -0
- data/lib/upjs/rails/{current_location.rb → request_echo_headers.rb} +4 -4
- data/lib/upjs/rails/{request.rb → request_ext.rb} +1 -1
- data/lib/upjs/rails/request_method_cookie.rb +28 -0
- data/lib/upjs/rails/version.rb +1 -1
- data/lib/upjs-rails.rb +3 -2
- data/spec_app/spec/javascripts/helpers/remove_body_margin.js.coffee +5 -0
- data/spec_app/spec/javascripts/up/flow_spec.js.coffee +3 -2
- data/spec_app/spec/javascripts/up/history_spec.js.coffee +0 -3
- data/spec_app/spec/javascripts/up/layout_spec.js.coffee +0 -3
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +27 -1
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +68 -22
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +15 -1
- metadata +6 -4
@@ -155,21 +155,49 @@ up.motion = (->
|
|
155
155
|
|
156
156
|
GHOSTING_PROMISE_KEY = 'up-ghosting-promise'
|
157
157
|
|
158
|
-
withGhosts = ($old, $new, block) ->
|
159
|
-
|
160
|
-
|
158
|
+
withGhosts = ($old, $new, options, block) ->
|
159
|
+
|
160
|
+
oldCopy = undefined
|
161
|
+
newCopy = undefined
|
162
|
+
oldScrollTop = undefined
|
163
|
+
newScrollTop = undefined
|
164
|
+
|
165
|
+
$viewport = up.layout.viewportOf($old)
|
161
166
|
|
162
167
|
u.temporaryCss $new, display: 'none', ->
|
163
|
-
|
168
|
+
# Within this block, $new is hidden but $old is visible
|
169
|
+
oldCopy = prependCopy($old, $viewport)
|
164
170
|
oldCopy.$ghost.addClass('up-destroying')
|
165
171
|
oldCopy.$bounds.addClass('up-destroying')
|
172
|
+
# Remember the previous scroll position in case we will reveal $new below.
|
173
|
+
oldScrollTop = $viewport.scrollTop()
|
174
|
+
# $viewport.scrollTop(oldScrollTop + 1)
|
175
|
+
|
166
176
|
u.temporaryCss $old, display: 'none', ->
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
177
|
+
# Within this block, $old is hidden but $new is visible
|
178
|
+
up.reveal($new, viewport: $viewport) if options.reveal
|
179
|
+
newCopy = prependCopy($new, $viewport)
|
180
|
+
newScrollTop = $viewport.scrollTop()
|
181
|
+
|
182
|
+
# Since we have scrolled the viewport (containing both $old and $new),
|
183
|
+
# we must shift the old copy so it looks like it it is still sitting
|
184
|
+
# in the same position.
|
185
|
+
oldCopy.moveTop(newScrollTop - oldScrollTop)
|
186
|
+
|
187
|
+
# Hide $old since we no longer need it.
|
188
|
+
$old.hide()
|
189
|
+
|
190
|
+
# We will let $new take up space in the element flow, but hide it.
|
191
|
+
# The user will only see the two animated ghosts until the transition
|
192
|
+
# is over.
|
193
|
+
showNew = u.temporaryCss($new, visibility: 'hidden')
|
194
|
+
|
172
195
|
promise = block(oldCopy.$ghost, newCopy.$ghost)
|
196
|
+
|
197
|
+
# Make a way to look at $old and $new and see if an animation is
|
198
|
+
# already in progress. If someone attempted a new animation on the
|
199
|
+
# same elements, the stored promises would be resolved by the second
|
200
|
+
# animation call, making the transition jump to the last frame instantly.
|
173
201
|
$old.data(GHOSTING_PROMISE_KEY, promise)
|
174
202
|
$new.data(GHOSTING_PROMISE_KEY, promise)
|
175
203
|
|
@@ -179,9 +207,6 @@ up.motion = (->
|
|
179
207
|
oldCopy.$bounds.remove()
|
180
208
|
newCopy.$bounds.remove()
|
181
209
|
# Now that the transition is over we show $new again.
|
182
|
-
# Since we expect $old to be removed in a heartbeat,
|
183
|
-
# $new should take up space
|
184
|
-
$old.css(display: 'none')
|
185
210
|
showNew()
|
186
211
|
|
187
212
|
promise
|
@@ -207,11 +232,11 @@ up.motion = (->
|
|
207
232
|
u.debug('Canceling existing ghosting on %o', $element)
|
208
233
|
existingGhosting.resolve?()
|
209
234
|
|
210
|
-
assertIsDeferred = (object,
|
235
|
+
assertIsDeferred = (object, source) ->
|
211
236
|
if u.isDeferred(object)
|
212
237
|
object
|
213
238
|
else
|
214
|
-
u.error("Did not return a promise with .then and .resolve methods: %o",
|
239
|
+
u.error("Did not return a promise with .then and .resolve methods: %o", source)
|
215
240
|
|
216
241
|
###*
|
217
242
|
Performs an animated transition between two elements.
|
@@ -252,25 +277,31 @@ up.motion = (->
|
|
252
277
|
The timing function that controls the transition's acceleration.
|
253
278
|
See [W3C documentation](http://www.w3.org/TR/css3-transitions/#transition-timing-function)
|
254
279
|
for a list of pre-defined timing functions.
|
280
|
+
@param {Boolean} [options.reveal=false]
|
281
|
+
Whether to reveal the new element by scrolling its parent viewport.
|
255
282
|
@return {Promise}
|
256
283
|
A promise for the transition's end.
|
257
284
|
###
|
258
285
|
morph = (source, target, transitionOrName, options) ->
|
259
286
|
if up.browser.canCssAnimation()
|
260
|
-
|
287
|
+
parsedOptions = u.only(options, 'reveal')
|
288
|
+
parsedOptions = u.extend(parsedOptions, animateOptions(options))
|
261
289
|
$old = $(source)
|
262
290
|
$new = $(target)
|
291
|
+
|
263
292
|
finish($old)
|
264
293
|
finish($new)
|
265
|
-
|
266
|
-
|
267
|
-
none()
|
268
|
-
else if transition = u.presence(transitionOrName, u.isFunction) || transitions[transitionOrName]
|
269
|
-
withGhosts $old, $new, ($oldGhost, $newGhost) ->
|
270
|
-
assertIsDeferred(transition($oldGhost, $newGhost, options), transitionOrName)
|
271
|
-
else if animation = animations[transitionOrName]
|
294
|
+
|
295
|
+
if transitionOrName == 'none' || transitionOrName == false || animation = animations[transitionOrName]
|
272
296
|
$old.hide()
|
273
|
-
|
297
|
+
# Since we can not longer rely on withGhosts to process options.reveal
|
298
|
+
# in this branch, we need to do it ourselves.
|
299
|
+
up.reveal($new) if options.reveal
|
300
|
+
animate($new, animation || 'none', options)
|
301
|
+
else if transition = u.presence(transitionOrName, u.isFunction) || transitions[transitionOrName]
|
302
|
+
withGhosts $old, $new, parsedOptions, ($oldGhost, $newGhost) ->
|
303
|
+
transitionPromise = transition($oldGhost, $newGhost, parsedOptions)
|
304
|
+
assertIsDeferred(transitionPromise, transitionOrName)
|
274
305
|
else if u.isString(transitionOrName) && transitionOrName.indexOf('/') >= 0
|
275
306
|
parts = transitionOrName.split('/')
|
276
307
|
transition = ($old, $new, options) ->
|
@@ -278,7 +309,7 @@ up.motion = (->
|
|
278
309
|
animate($old, parts[0], options),
|
279
310
|
animate($new, parts[1], options)
|
280
311
|
)
|
281
|
-
morph($old, $new, transition,
|
312
|
+
morph($old, $new, transition, parsedOptions)
|
282
313
|
else
|
283
314
|
u.error("Unknown transition %o", transitionOrName)
|
284
315
|
else
|
@@ -289,7 +320,7 @@ up.motion = (->
|
|
289
320
|
###*
|
290
321
|
@private
|
291
322
|
###
|
292
|
-
|
323
|
+
prependCopy = ($element, $viewport) ->
|
293
324
|
elementDims = u.measure($element, relative: true, inner: true)
|
294
325
|
|
295
326
|
$ghost = $element.clone()
|
@@ -313,16 +344,29 @@ up.motion = (->
|
|
313
344
|
$bounds.css(position: 'absolute')
|
314
345
|
$bounds.css(elementDims)
|
315
346
|
|
347
|
+
top = elementDims.top
|
348
|
+
|
349
|
+
moveTop = (diff) ->
|
350
|
+
if diff != 0
|
351
|
+
top += diff
|
352
|
+
$bounds.css(top: top)
|
353
|
+
|
316
354
|
$ghost.appendTo($bounds)
|
317
355
|
$bounds.insertBefore($element)
|
318
356
|
|
319
|
-
#
|
320
|
-
#
|
321
|
-
|
322
|
-
$
|
357
|
+
# In theory, $ghost should now sit over $element perfectly.
|
358
|
+
# However, $element might collapse its margin against a previous sibling
|
359
|
+
# element, and $ghost does not have the same sibling.
|
360
|
+
# So we manually correct $ghost's top position so it aligns with $element.
|
361
|
+
moveTop($element.offset().top - $ghost.offset().top)
|
362
|
+
|
363
|
+
$fixedElements = up.layout.fixedChildren($ghost)
|
364
|
+
for fixedElement in $fixedElements
|
365
|
+
u.fixedToAbsolute(fixedElement, $viewport)
|
323
366
|
|
324
367
|
$ghost: $ghost
|
325
368
|
$bounds: $bounds
|
369
|
+
moveTop: moveTop
|
326
370
|
|
327
371
|
###*
|
328
372
|
Defines a named transition.
|
@@ -543,7 +587,7 @@ up.motion = (->
|
|
543
587
|
defaults: config.update
|
544
588
|
none: none
|
545
589
|
when: resolvableWhen
|
546
|
-
|
590
|
+
prependCopy: prependCopy
|
547
591
|
|
548
592
|
)()
|
549
593
|
|
@@ -254,8 +254,12 @@ up.popup = (->
|
|
254
254
|
@ujs
|
255
255
|
###
|
256
256
|
up.on('click', '[up-close]', (event, $element) ->
|
257
|
-
if $element.closest('.up-popup')
|
257
|
+
if $element.closest('.up-popup').length
|
258
258
|
close()
|
259
|
+
# Only prevent the default when we actually closed a popup.
|
260
|
+
# This way we can have buttons that close a popup when within a popup,
|
261
|
+
# but link to a destination if not.
|
262
|
+
event.preventDefault()
|
259
263
|
)
|
260
264
|
|
261
265
|
# The framework is reset between tests
|
@@ -189,6 +189,8 @@ up.proxy = (->
|
|
189
189
|
else
|
190
190
|
promise = load(request)
|
191
191
|
set(request, promise)
|
192
|
+
# Don't cache failed requests
|
193
|
+
promise.fail -> remove(request)
|
192
194
|
|
193
195
|
if pending && !options.preload
|
194
196
|
# This will actually make `pendingCount` higher than the actual
|
@@ -529,24 +529,38 @@ up.util = (->
|
|
529
529
|
if existingAnimation = $(this).data(ANIMATION_PROMISE_KEY)
|
530
530
|
existingAnimation.resolve()
|
531
531
|
|
532
|
-
measure = ($element,
|
533
|
-
|
534
|
-
|
532
|
+
measure = ($element, opts) ->
|
533
|
+
opts = options(opts, relative: false, inner: false, full: false)
|
534
|
+
|
535
|
+
if opts.relative
|
536
|
+
if opts.relative == true
|
537
|
+
coordinates = $element.position()
|
538
|
+
else
|
539
|
+
$context = $(opts.relative)
|
540
|
+
elementCoords = $element.offset()
|
541
|
+
if $context.is(document)
|
542
|
+
# The document is always at the origin
|
543
|
+
coordinates = elementCoords
|
544
|
+
else
|
545
|
+
contextCoords = $context.offset()
|
546
|
+
coordinates =
|
547
|
+
left: elementCoords.left - contextCoords.left
|
548
|
+
top: elementCoords.top - contextCoords.top
|
535
549
|
else
|
536
|
-
$element.offset()
|
550
|
+
coordinates = $element.offset()
|
537
551
|
|
538
552
|
box =
|
539
553
|
left: coordinates.left
|
540
554
|
top: coordinates.top
|
541
555
|
|
542
|
-
if
|
556
|
+
if opts.inner
|
543
557
|
box.width = $element.width()
|
544
558
|
box.height = $element.height()
|
545
559
|
else
|
546
560
|
box.width = $element.outerWidth()
|
547
561
|
box.height = $element.outerHeight()
|
548
562
|
|
549
|
-
if
|
563
|
+
if opts.full
|
550
564
|
viewport = clientSize()
|
551
565
|
box.right = viewport.width - (box.left + box.width)
|
552
566
|
box.bottom = viewport.height - (box.top + box.height)
|
@@ -838,6 +852,33 @@ up.util = (->
|
|
838
852
|
parent.insertBefore(wrappedNode, wrapper)
|
839
853
|
parent.removeChild(wrapper)
|
840
854
|
|
855
|
+
offsetParent = ($element) ->
|
856
|
+
$match = undefined
|
857
|
+
while ($element = $element.parent()) && $element.length
|
858
|
+
position = $element.css('position')
|
859
|
+
console.log("Iteration element is %o with position %o", $element, position)
|
860
|
+
if position == 'absolute' || position == 'relative' || $element.is('body')
|
861
|
+
$match = $element
|
862
|
+
break
|
863
|
+
$match
|
864
|
+
|
865
|
+
fixedToAbsolute = (element, $viewport) ->
|
866
|
+
$element = $(element)
|
867
|
+
$futureOffsetParent = offsetParent($element)
|
868
|
+
# To get a fixed elements distance from the edge of the screen,
|
869
|
+
# use position(), not offset(). offset() would include the current
|
870
|
+
# scrollTop of the viewport.
|
871
|
+
elementCoords = $element.position()
|
872
|
+
futureParentCoords = $futureOffsetParent.offset()
|
873
|
+
$element.css
|
874
|
+
position: 'absolute'
|
875
|
+
left: elementCoords.left - futureParentCoords.left
|
876
|
+
top: elementCoords.top - futureParentCoords.top + $viewport.scrollTop()
|
877
|
+
right: ''
|
878
|
+
bottom: ''
|
879
|
+
|
880
|
+
offsetParent: offsetParent
|
881
|
+
fixedToAbsolute: fixedToAbsolute
|
841
882
|
presentAttr: presentAttr
|
842
883
|
createElement: createElement
|
843
884
|
normalizeUrl: normalizeUrl
|
@@ -3,3 +3,4 @@ defaults = up.layout.defaults()
|
|
3
3
|
up.layout.defaults
|
4
4
|
fixedTop: defaults.fixedTop.concat(['.navbar-fixed-top'])
|
5
5
|
fixedBottom: defaults.fixedBottom.concat(['.navbar-fixed-bottom'])
|
6
|
+
anchoredRight: defaults.anchoredRight.concat(['.navbar-fixed-top', '.navbar-fixed-bottom', '.footer'])
|
@@ -1,19 +1,19 @@
|
|
1
1
|
module Upjs
|
2
2
|
module Rails
|
3
|
-
module
|
3
|
+
module RequestEchoHeaders
|
4
4
|
|
5
5
|
def self.included(base)
|
6
|
-
base.before_filter :
|
6
|
+
base.before_filter :set_up_request_echo_headers
|
7
7
|
end
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
|
-
def
|
11
|
+
def set_up_request_echo_headers
|
12
12
|
headers['X-Up-Location'] = request.original_url
|
13
13
|
headers['X-Up-Method'] = request.method
|
14
14
|
end
|
15
15
|
|
16
|
-
ActionController::Base.include
|
16
|
+
ActionController::Base.send(:include, self)
|
17
17
|
|
18
18
|
end
|
19
19
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# See
|
2
|
+
# https://github.com/rails/turbolinks/search?q=request_method&ref=cmdform
|
3
|
+
# https://github.com/rails/turbolinks/blob/83d4b3d2c52a681f07900c28adb28bc8da604733/README.md#initialization
|
4
|
+
module Upjs
|
5
|
+
module Rails
|
6
|
+
module RequestMethod
|
7
|
+
|
8
|
+
COOKIE_NAME = '_up_request_method'
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.before_filter :set_up_request_method_cookie
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def set_up_request_method_cookie
|
17
|
+
if request.get?
|
18
|
+
cookies.delete(COOKIE_NAME)
|
19
|
+
else
|
20
|
+
cookies[COOKIE_NAME] = request.request_method
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
ActionController::Base.send(:include, self)
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/upjs/rails/version.rb
CHANGED
data/lib/upjs-rails.rb
CHANGED
@@ -124,11 +124,12 @@ describe 'up.flow', ->
|
|
124
124
|
@revealedHTML = $revealedElement.get(0).outerHTML
|
125
125
|
u.resolvedPromise()
|
126
126
|
|
127
|
-
it 'reveals
|
127
|
+
it 'reveals a new element before it is being replaced', (done) ->
|
128
128
|
@request = up.replace('.middle', '/path', reveal: true)
|
129
129
|
@respond()
|
130
130
|
@request.then =>
|
131
|
-
expect(up.reveal).toHaveBeenCalledWith(@oldMiddle)
|
131
|
+
expect(up.reveal).not.toHaveBeenCalledWith(@oldMiddle)
|
132
|
+
expect(@revealedHTML).toContain('new-middle')
|
132
133
|
done()
|
133
134
|
|
134
135
|
it 'reveals a new element that is being appended', (done) ->
|
@@ -16,11 +16,8 @@ describe 'up.history', ->
|
|
16
16
|
|
17
17
|
it 'sets an [up-href] attribute to the previous URL and sets the up-restore-scroll attribute to "true"', ->
|
18
18
|
up.history.push('/one')
|
19
|
-
console.log("url is now %o, previous was %o", up.history.url(), up.history.previousUrl())
|
20
19
|
up.history.push('/two')
|
21
|
-
console.log("url is now %o, previous was %o", up.history.url(), up.history.previousUrl())
|
22
20
|
$element = up.ready(affix('a[href="/three"][up-back]').text('text'))
|
23
|
-
console.log("url is now %o, previous was %o", up.history.url(), up.history.previousUrl())
|
24
21
|
expect($element.attr('href')).toEndWith('/three')
|
25
22
|
expect($element.attr('up-href')).toEndWith('/one')
|
26
23
|
expect($element.attr('up-restore-scroll')).toBe('')
|
@@ -17,8 +17,6 @@ describe 'up.layout', ->
|
|
17
17
|
beforeEach ->
|
18
18
|
$body = $('body')
|
19
19
|
|
20
|
-
@restoreMargin = u.temporaryCss($body, 'margin-top': 0)
|
21
|
-
|
22
20
|
@$elements = []
|
23
21
|
@$container = $('<div class="container">').prependTo($body)
|
24
22
|
|
@@ -31,7 +29,6 @@ describe 'up.layout', ->
|
|
31
29
|
|
32
30
|
afterEach ->
|
33
31
|
@$container.remove()
|
34
|
-
@restoreMargin()
|
35
32
|
|
36
33
|
it 'reveals the given element', ->
|
37
34
|
up.reveal(@$elements[0])
|
@@ -8,6 +8,8 @@ describe 'up.modal', ->
|
|
8
8
|
|
9
9
|
describe 'up.modal.open', ->
|
10
10
|
|
11
|
+
assumedScrollbarWidth = 15
|
12
|
+
|
11
13
|
it "loads the given link's destination in a dialog window", (done) ->
|
12
14
|
$link = affix('a[href="/path/to"][up-modal=".middle"]').text('link')
|
13
15
|
promise = up.modal.open($link)
|
@@ -49,7 +51,7 @@ describe 'up.modal', ->
|
|
49
51
|
expect($modal).toExist()
|
50
52
|
expect($modal.css('overflow-y')).toEqual('scroll')
|
51
53
|
expect($body.css('overflow-y')).toEqual('hidden')
|
52
|
-
expect(parseInt($body.css('padding-right'))).toBeAround(
|
54
|
+
expect(parseInt($body.css('padding-right'))).toBeAround(assumedScrollbarWidth, 10)
|
53
55
|
|
54
56
|
up.modal.close().then ->
|
55
57
|
expect($body.css('overflow-y')).toEqual('scroll')
|
@@ -57,6 +59,30 @@ describe 'up.modal', ->
|
|
57
59
|
|
58
60
|
done()
|
59
61
|
|
62
|
+
it 'pushes right-anchored elements away from the edge of the screen in order to prevent jumping', (done) ->
|
63
|
+
|
64
|
+
$anchoredElement = affix('div[up-anchored=right]').css
|
65
|
+
position: 'absolute'
|
66
|
+
top: '0'
|
67
|
+
right: '30px'
|
68
|
+
|
69
|
+
promise = up.modal.open(url: '/foo', target: '.container')
|
70
|
+
|
71
|
+
@lastRequest().respondWith
|
72
|
+
status: 200
|
73
|
+
contentType: 'text/html'
|
74
|
+
responseText:
|
75
|
+
"""
|
76
|
+
<div class="container">text</div>
|
77
|
+
"""
|
78
|
+
|
79
|
+
promise.then ->
|
80
|
+
expect(parseInt($anchoredElement.css('right'))).toBeAround(30 + assumedScrollbarWidth, 10)
|
81
|
+
|
82
|
+
up.modal.close().then ->
|
83
|
+
expect(parseInt($anchoredElement.css('right'))).toBeAround(30 , 10)
|
84
|
+
done()
|
85
|
+
|
60
86
|
describe 'up.modal.close', ->
|
61
87
|
|
62
88
|
it 'should have tests'
|
@@ -37,7 +37,7 @@ describe 'up.motion', ->
|
|
37
37
|
|
38
38
|
if up.browser.canCssAnimation()
|
39
39
|
|
40
|
-
it 'transitions between two element
|
40
|
+
it 'transitions between two element by animating two copies while keeping the originals in the background', (done) ->
|
41
41
|
|
42
42
|
$old = affix('.old').text('old content').css(
|
43
43
|
position: 'absolute'
|
@@ -53,7 +53,7 @@ describe 'up.motion', ->
|
|
53
53
|
width: '22px',
|
54
54
|
height: '23px'
|
55
55
|
)
|
56
|
-
up.morph($old, $new, 'cross-fade', duration:
|
56
|
+
up.morph($old, $new, 'cross-fade', duration: 200, easing: 'linear')
|
57
57
|
|
58
58
|
# The actual animation will be performed on Ghosts since
|
59
59
|
# two element usually cannot exist in the DOM at the same time
|
@@ -76,14 +76,12 @@ describe 'up.motion', ->
|
|
76
76
|
|
77
77
|
# The actual elements are hidden, but $old will take up its original
|
78
78
|
# space until the animation completes.
|
79
|
-
expect($old.css(
|
79
|
+
expect($old.css('display')).toEqual('none')
|
80
|
+
|
81
|
+
expect($new.css(['display', 'visibility'])).toEqual(
|
80
82
|
display: 'block',
|
81
83
|
visibility: 'hidden'
|
82
84
|
)
|
83
|
-
expect($new.css(['display', 'visibility'])).toEqual(
|
84
|
-
display: 'none',
|
85
|
-
visibility: 'visible'
|
86
|
-
)
|
87
85
|
|
88
86
|
# Ghosts will hover over $old and $new using absolute positioning,
|
89
87
|
# matching the coordinates of the original elements.
|
@@ -108,15 +106,15 @@ describe 'up.motion', ->
|
|
108
106
|
expect(opacity($newGhost)).toBeAround(0.0, 0.25)
|
109
107
|
expect(opacity($oldGhost)).toBeAround(1.0, 0.25)
|
110
108
|
|
111
|
-
@setTimer
|
109
|
+
@setTimer 80, ->
|
112
110
|
expect(opacity($newGhost)).toBeAround(0.4, 0.25)
|
113
111
|
expect(opacity($oldGhost)).toBeAround(0.6, 0.25)
|
114
112
|
|
115
|
-
@setTimer
|
113
|
+
@setTimer 140, ->
|
116
114
|
expect(opacity($newGhost)).toBeAround(0.7, 0.25)
|
117
115
|
expect(opacity($oldGhost)).toBeAround(0.3, 0.25)
|
118
116
|
|
119
|
-
@setTimer
|
117
|
+
@setTimer 250, ->
|
120
118
|
# Once our two ghosts have rendered their visual effect,
|
121
119
|
# we remove them from the DOM.
|
122
120
|
expect($newGhost).not.toBeInDOM()
|
@@ -124,10 +122,7 @@ describe 'up.motion', ->
|
|
124
122
|
|
125
123
|
# The old element is still in the DOM, but hidden.
|
126
124
|
# Morphing does *not* remove the target element.
|
127
|
-
expect($old.css(
|
128
|
-
display: 'none',
|
129
|
-
visibility: 'hidden'
|
130
|
-
)
|
125
|
+
expect($old.css('display')).toEqual('none')
|
131
126
|
expect($new.css(['display', 'visibility'])).toEqual(
|
132
127
|
display: 'block',
|
133
128
|
visibility: 'visible'
|
@@ -150,6 +145,39 @@ describe 'up.motion', ->
|
|
150
145
|
# Check that it's a different ghosts
|
151
146
|
expect($ghost2).not.toEqual($ghost1)
|
152
147
|
|
148
|
+
describe 'with { reveal: true } option', ->
|
149
|
+
|
150
|
+
it 'reveals the new element while making the old element within the same viewport appear as if it would keep its scroll position', ->
|
151
|
+
$container = affix('.container[up-viewport]').css
|
152
|
+
'width': '200px'
|
153
|
+
'height': '200px'
|
154
|
+
'overflow-y': 'scroll'
|
155
|
+
'position': 'fixed'
|
156
|
+
'left': 0,
|
157
|
+
'top': 0
|
158
|
+
$old = affix('.old').appendTo($container).css(height: '600px')
|
159
|
+
$container.scrollTop(300)
|
160
|
+
|
161
|
+
$new = affix('.new').insertBefore($old).css(height: '600px')
|
162
|
+
|
163
|
+
up.morph($old, $new, 'cross-fade', duration: 50, reveal: true)
|
164
|
+
|
165
|
+
$oldGhost = $('.old.up-ghost')
|
166
|
+
$newGhost = $('.new.up-ghost')
|
167
|
+
|
168
|
+
# Container is scrolled up due to { reveal: true } option.
|
169
|
+
# Since $old and $new are sitting in the same viewport with a
|
170
|
+
# single shares scrollbar This will make the ghost for $old jump.
|
171
|
+
expect($container.scrollTop()).toEqual(0)
|
172
|
+
|
173
|
+
# See that the ghost for $new is aligned with the top edge
|
174
|
+
# of the viewport.
|
175
|
+
expect($newGhost.offset().top).toEqual(0)
|
176
|
+
|
177
|
+
# The ghost for $old is shifted upwards to make it looks like it
|
178
|
+
# was at the scroll position before we revealed $new.
|
179
|
+
expect($oldGhost.offset().top).toEqual(-300)
|
180
|
+
|
153
181
|
else
|
154
182
|
|
155
183
|
it "doesn't animate and hides the first element instead", ->
|
@@ -171,14 +199,14 @@ describe 'up.motion', ->
|
|
171
199
|
|
172
200
|
it 'should have tests'
|
173
201
|
|
174
|
-
describe 'up.motion.
|
202
|
+
describe 'up.motion.prependCopy', ->
|
175
203
|
|
176
204
|
afterEach ->
|
177
205
|
$('.up-bounds, .up-ghost, .fixture').remove()
|
178
206
|
|
179
207
|
it 'clones the given element into a .up-ghost-bounds container and inserts it as a sibling before the element', ->
|
180
208
|
$element = affix('.element').text('element text')
|
181
|
-
up.motion.
|
209
|
+
up.motion.prependCopy($element)
|
182
210
|
$bounds = $element.prev()
|
183
211
|
expect($bounds).toExist()
|
184
212
|
expect($bounds).toHaveClass('up-bounds')
|
@@ -190,13 +218,13 @@ describe 'up.motion', ->
|
|
190
218
|
it 'removes <script> tags from the cloned element', ->
|
191
219
|
$element = affix('.element')
|
192
220
|
$('<script></script>').appendTo($element)
|
193
|
-
up.motion.
|
221
|
+
up.motion.prependCopy($element)
|
194
222
|
$ghost = $('.up-ghost')
|
195
223
|
expect($ghost.find('script')).not.toExist()
|
196
224
|
|
197
225
|
it 'absolutely positions the ghost over the given element', ->
|
198
226
|
$element = affix('.element')
|
199
|
-
up.motion.
|
227
|
+
up.motion.prependCopy($element)
|
200
228
|
$ghost = $('.up-ghost')
|
201
229
|
expect($ghost.offset()).toEqual($element.offset())
|
202
230
|
expect($ghost.width()).toEqual($element.width())
|
@@ -204,25 +232,43 @@ describe 'up.motion', ->
|
|
204
232
|
|
205
233
|
it 'accurately positions the ghost over an element with margins', ->
|
206
234
|
$element = affix('.element').css(margin: '40px')
|
207
|
-
up.motion.
|
235
|
+
up.motion.prependCopy($element)
|
208
236
|
$ghost = $('.up-ghost')
|
209
237
|
expect($ghost.offset()).toEqual($element.offset())
|
210
238
|
|
211
239
|
it "doesn't change the position of a child whose margins no longer collapse", ->
|
212
240
|
$element = affix('.element')
|
213
241
|
$child = $('<div class="child"></div>').css(margin: '40px').appendTo($element)
|
214
|
-
up.motion.
|
242
|
+
up.motion.prependCopy($element)
|
215
243
|
$clonedChild = $('.up-ghost .child')
|
216
244
|
expect($clonedChild.offset()).toEqual($child.offset())
|
217
245
|
|
218
246
|
it 'correctly positions the ghost over an element within a scrolled body', ->
|
219
|
-
$body = $('body')
|
247
|
+
$body = $('body')
|
220
248
|
$element1 = $('<div class="fixture"></div>').css(height: '75px').prependTo($body)
|
221
249
|
$element2 = $('<div class="fixture"></div>').css(height: '100px').insertAfter($element1)
|
222
250
|
$body.scrollTop(17)
|
223
|
-
{ $bounds, $ghost } = up.motion.
|
251
|
+
{ $bounds, $ghost } = up.motion.prependCopy($element2)
|
224
252
|
expect($bounds.css('position')).toBe('absolute')
|
225
253
|
expect($bounds.css('top')).toEqual('75px')
|
226
254
|
expect($ghost.css('position')).toBe('static')
|
227
255
|
|
228
256
|
it 'correctly positions the ghost over an element within a viewport with overflow-y: scroll'
|
257
|
+
|
258
|
+
it 'converts fixed elements within the copies to absolutely positioning', ->
|
259
|
+
$element = affix('.element').css
|
260
|
+
position: 'absolute'
|
261
|
+
top: '50px'
|
262
|
+
left: '50px'
|
263
|
+
$fixedChild = $('<div class="fixed-child" up-fixed></div>').css
|
264
|
+
position: 'fixed'
|
265
|
+
left: '77px'
|
266
|
+
top: '77px'
|
267
|
+
$fixedChild.appendTo($element)
|
268
|
+
up.motion.prependCopy($element, $('body'))
|
269
|
+
$fixedChildGhost = $('.up-ghost .fixed-child')
|
270
|
+
expect($fixedChildGhost.css(['position', 'left', 'top'])).toEqual
|
271
|
+
position: 'absolute',
|
272
|
+
left: '27px',
|
273
|
+
top: '27px'
|
274
|
+
|