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
@@ -840,6 +840,24 @@ up.util = (($) ->
|
|
840
840
|
$outer.remove()
|
841
841
|
width
|
842
842
|
|
843
|
+
###*
|
844
|
+
Returns whether the given element is currently showing a vertical scrollbar.
|
845
|
+
|
846
|
+
@function up.util.documentHasVerticalScrollbar
|
847
|
+
@internal
|
848
|
+
###
|
849
|
+
documentHasVerticalScrollbar = ->
|
850
|
+
body = document.body
|
851
|
+
$body = $(body)
|
852
|
+
html = document.documentElement
|
853
|
+
|
854
|
+
bodyOverflow = $body.css('overflow-y')
|
855
|
+
|
856
|
+
forcedScroll = (bodyOverflow == 'scroll')
|
857
|
+
forcedHidden = (bodyOverflow == 'hidden')
|
858
|
+
|
859
|
+
forcedScroll || (!forcedHidden && html.scrollHeight > html.clientHeight)
|
860
|
+
|
843
861
|
###*
|
844
862
|
Modifies the given function so it only runs once.
|
845
863
|
Subsequent calls will return the previous return value.
|
@@ -935,6 +953,9 @@ up.util = (($) ->
|
|
935
953
|
###
|
936
954
|
cssAnimate = (elementOrSelector, lastFrame, opts) ->
|
937
955
|
$element = $(elementOrSelector)
|
956
|
+
|
957
|
+
# Don't name the local variable `options` since that would override
|
958
|
+
# the `options` function in our scope. We really need `let` :(
|
938
959
|
opts = options(opts,
|
939
960
|
duration: 300,
|
940
961
|
delay: 0,
|
@@ -944,14 +965,32 @@ up.util = (($) ->
|
|
944
965
|
# We don't finish an existing animation here, since the public API
|
945
966
|
# we expose as `up.motion.animate` already does this.
|
946
967
|
deferred = $.Deferred()
|
968
|
+
|
969
|
+
transitionProperties = Object.keys(lastFrame)
|
947
970
|
transition =
|
948
|
-
'transition-property':
|
971
|
+
'transition-property': transitionProperties.join(', ')
|
949
972
|
'transition-duration': "#{opts.duration}ms"
|
950
973
|
'transition-delay': "#{opts.delay}ms"
|
951
974
|
'transition-timing-function': opts.easing
|
952
975
|
oldTransition = $element.css(Object.keys(transition))
|
953
976
|
|
954
977
|
$element.addClass('up-animating')
|
978
|
+
|
979
|
+
transitionFinished = ->
|
980
|
+
$element.removeClass('up-animating')
|
981
|
+
$element.off('transitionend', onTransitionEnd)
|
982
|
+
|
983
|
+
onTransitionEnd = (event) ->
|
984
|
+
completedProperty = event.originalEvent.propertyName
|
985
|
+
if contains(transitionProperties, completedProperty)
|
986
|
+
deferred.resolve() # unless isDetached($element)
|
987
|
+
transitionFinished()
|
988
|
+
|
989
|
+
$element.on('transitionend', onTransitionEnd)
|
990
|
+
|
991
|
+
# Clean up in case we're canceled through some other code that resolves our deferred.
|
992
|
+
deferred.then(transitionFinished)
|
993
|
+
|
955
994
|
withoutCompositing = forceCompositing($element)
|
956
995
|
$element.css(transition)
|
957
996
|
$element.css(lastFrame)
|
@@ -963,26 +1002,20 @@ up.util = (($) ->
|
|
963
1002
|
|
964
1003
|
# To interrupt the running transition we *must* set it to 'none' exactly.
|
965
1004
|
# We cannot simply restore the old transition properties because browsers
|
966
|
-
# would simply keep transitioning
|
1005
|
+
# would simply keep transitioning.
|
967
1006
|
$element.css('transition': 'none')
|
968
1007
|
|
969
|
-
# Restoring a previous transition involves
|
1008
|
+
# Restoring a previous transition involves forcing a repaint, so we only do it if
|
970
1009
|
# we know the element was transitioning before.
|
1010
|
+
# Note that the default transition for elements is actually "all 0s ease 0s"
|
1011
|
+
# instead of "none", although that has the same effect as "none".
|
971
1012
|
hadTransitionBefore = !(oldTransition['transition-property'] == 'none' || (oldTransition['transition-property'] == 'all' && oldTransition['transition-duration'][0] == '0'))
|
972
1013
|
if hadTransitionBefore
|
1014
|
+
# If there is no repaint between the "none" transition and restoring
|
1015
|
+
# the previous transition, the browser will simply keep transitioning.
|
973
1016
|
forceRepaint($element) # :(
|
974
1017
|
$element.css(oldTransition)
|
975
1018
|
|
976
|
-
# Since listening to transitionEnd events is painful, we wait for a timeout
|
977
|
-
# and then resolve our deferred. Maybe revisit that decision some day.
|
978
|
-
animationEnd = opts.duration + opts.delay
|
979
|
-
endTimeout = setTimer animationEnd, ->
|
980
|
-
$element.removeClass('up-animating')
|
981
|
-
deferred.resolve() unless isDetached($element)
|
982
|
-
# Clean up in case we're canceled through some other code that
|
983
|
-
# resolves our deferred.
|
984
|
-
deferred.then(-> clearTimeout(endTimeout))
|
985
|
-
|
986
1019
|
# Return the whole deferred and not just return a thenable.
|
987
1020
|
# Other code will need the possibility to cancel the animation
|
988
1021
|
# by resolving the deferred.
|
@@ -1652,6 +1685,13 @@ up.util = (($) ->
|
|
1652
1685
|
else
|
1653
1686
|
{}
|
1654
1687
|
|
1688
|
+
opacity = (element) ->
|
1689
|
+
rawOpacity = $(element).css('opacity')
|
1690
|
+
if isGiven(rawOpacity)
|
1691
|
+
parseFloat(rawOpacity)
|
1692
|
+
else
|
1693
|
+
undefined
|
1694
|
+
|
1655
1695
|
###*
|
1656
1696
|
Returns whether the given element has been detached from the DOM
|
1657
1697
|
(or whether it was never attached).
|
@@ -1752,6 +1792,7 @@ up.util = (($) ->
|
|
1752
1792
|
remove: remove
|
1753
1793
|
memoize: memoize
|
1754
1794
|
scrollbarWidth: scrollbarWidth
|
1795
|
+
documentHasVerticalScrollbar: documentHasVerticalScrollbar
|
1755
1796
|
config: config
|
1756
1797
|
cache: cache
|
1757
1798
|
unwrapElement: unwrapElement
|
@@ -1762,6 +1803,7 @@ up.util = (($) ->
|
|
1762
1803
|
extractOptions: extractOptions
|
1763
1804
|
isDetached: isDetached
|
1764
1805
|
noop: noop
|
1806
|
+
opacity: opacity
|
1765
1807
|
|
1766
1808
|
)($)
|
1767
1809
|
|
@@ -1,48 +1,64 @@
|
|
1
|
-
$stratum
|
2
|
-
$stratum-elements: 11000
|
1
|
+
$stratum: 10000
|
3
2
|
|
4
|
-
// These could actually be 1000, 2000, 3000 and 4000 since the `fixed` position of
|
3
|
+
// These could actually be 1000, 2000, 3000 and 4000 since the `fixed` position of an element defines
|
5
4
|
// a stacking context for all contained z-indexes.
|
6
5
|
//
|
7
6
|
// However, let's keep the option open that these elements will one day not have its stacking context.
|
8
7
|
//
|
9
8
|
// Also let's not do 1, 2, 3 and 4 so other elements have a chance to move themselves between the layers.
|
10
|
-
$substratum-
|
11
|
-
$substratum-
|
12
|
-
$substratum-
|
9
|
+
$substratum-backdrop: 11000
|
10
|
+
$substratum-elements: 12000
|
11
|
+
$substratum-dialog: 13000
|
12
|
+
$substratum-content: 14000
|
13
|
+
$substratum-close: 15000
|
13
14
|
|
14
15
|
$close-height: 36px
|
15
16
|
$close-width: 36px
|
16
17
|
$close-font-size: 34px
|
17
18
|
|
18
19
|
.up-modal
|
20
|
+
position: fixed
|
21
|
+
top: 0
|
22
|
+
left: 0
|
23
|
+
bottom: 0
|
24
|
+
right: 0
|
25
|
+
z-index: $stratum
|
26
|
+
overflow-x: hidden
|
19
27
|
|
20
28
|
.up-modal-backdrop
|
21
|
-
z-index: $
|
29
|
+
z-index: $substratum-backdrop
|
22
30
|
background-color: rgba(90, 90, 90, 0.4)
|
23
|
-
position:
|
31
|
+
position: absolute
|
24
32
|
top: 0
|
25
33
|
right: 0
|
26
34
|
bottom: 0
|
27
35
|
left: 0
|
28
36
|
|
29
37
|
.up-modal-viewport
|
30
|
-
|
31
|
-
position: fixed
|
38
|
+
position: absolute
|
32
39
|
top: 0
|
33
40
|
left: 0
|
34
41
|
bottom: 0
|
35
42
|
right: 0
|
43
|
+
z-index: $substratum-elements
|
36
44
|
overflow-x: hidden
|
37
|
-
|
45
|
+
// The viewport always has a scrollbar, except when we're animating (see below)
|
46
|
+
overflow-y: scroll
|
38
47
|
// We prefer centering the dialog as an `inline-block`
|
39
48
|
// to giving it a horizontal margin of `auto`. This way
|
40
49
|
// the width of `.up-modal-dialog` is controlled by the
|
41
50
|
// contents of `.up-modal-content`.
|
42
51
|
text-align: center
|
43
52
|
|
44
|
-
|
53
|
+
.up-modal.up-modal-animating
|
54
|
+
// During opening/closing animations we let the .up-modal container take over
|
55
|
+
// the scrollbars that would usually be owned by .up-modal-viewport.
|
56
|
+
// If .up-modal-viewport had a scrollbar while animating with
|
57
|
+
// "zoom-in" it would look strange that the scrollbar is scaled.
|
58
|
+
&
|
45
59
|
overflow-y: scroll
|
60
|
+
.up-modal-viewport
|
61
|
+
overflow-y: hidden
|
46
62
|
|
47
63
|
.up-modal-dialog
|
48
64
|
z-index: $substratum-dialog
|
@@ -35,6 +35,32 @@ module Unpoly
|
|
35
35
|
request.headers['X-Up-Target']
|
36
36
|
end
|
37
37
|
|
38
|
+
##
|
39
|
+
# Tests whether the given CSS selector is targeted by the current fragment update.
|
40
|
+
#
|
41
|
+
# Note that the matching logic is very simplistic and does not actually know
|
42
|
+
# how your page layout is structured. It will return `true` if
|
43
|
+
# the tested selector and the requested CSS selector matches exactly, or if the
|
44
|
+
# requested selector is `body` or `html`.
|
45
|
+
#
|
46
|
+
# Always returns `true` if the current request is not an Unpoly fragment update.
|
47
|
+
def target?(tested_target)
|
48
|
+
if up?
|
49
|
+
actual_target = target
|
50
|
+
if actual_target == tested_target
|
51
|
+
true
|
52
|
+
elsif actual_target == 'html'
|
53
|
+
true
|
54
|
+
elsif actual_target == 'body'
|
55
|
+
not ['head', 'title', 'meta'].include?(tested_target)
|
56
|
+
else
|
57
|
+
false
|
58
|
+
end
|
59
|
+
else
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
38
64
|
##
|
39
65
|
# Returns whether the current form submission should be
|
40
66
|
# [validated](http://unpoly.com/up-validate) (and not be saved to the database).
|
data/lib/unpoly/rails/version.rb
CHANGED
data/spec_app/Gemfile.lock
CHANGED
@@ -8,6 +8,12 @@ class BindingTestController < ActionController::Base
|
|
8
8
|
render :text => up.target
|
9
9
|
end
|
10
10
|
|
11
|
+
def up_is_target
|
12
|
+
tested_target = params[:tested_target].presence
|
13
|
+
tested_target or raise "No target given"
|
14
|
+
render :text => up.target?(tested_target).to_s
|
15
|
+
end
|
16
|
+
|
11
17
|
def is_up_validate
|
12
18
|
render :text => up.validate?.to_s
|
13
19
|
end
|
@@ -17,7 +17,7 @@ describe BindingTestController do
|
|
17
17
|
|
18
18
|
describe '#up' do
|
19
19
|
|
20
|
-
describe '#
|
20
|
+
describe '#target' do
|
21
21
|
|
22
22
|
it 'returns the CSS selector that is requested via Unpoly' do
|
23
23
|
request.headers['X-Up-Target'] = '.foo'
|
@@ -27,6 +27,87 @@ describe BindingTestController do
|
|
27
27
|
|
28
28
|
end
|
29
29
|
|
30
|
+
describe '#target?' do
|
31
|
+
|
32
|
+
it 'returns true if the tested CSS selector is requested via Unpoly' do
|
33
|
+
request.headers['X-Up-Target'] = '.foo'
|
34
|
+
get :up_is_target, tested_target: '.foo'
|
35
|
+
expect(response.body).to eq('true')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns false if Unpoly is requesting another CSS selector' do
|
39
|
+
request.headers['X-Up-Target'] = '.bar'
|
40
|
+
get :up_is_target, tested_target: '.foo'
|
41
|
+
expect(response.body).to eq('false')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns true if the request is not an Unpoly request' do
|
45
|
+
get :up_is_target, tested_target: '.foo'
|
46
|
+
expect(response.body).to eq('true')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns true if testing a custom selector, and Unpoly requests "body"' do
|
50
|
+
request.headers['X-Up-Target'] = 'body'
|
51
|
+
get :up_is_target, tested_target: '.foo'
|
52
|
+
expect(response.body).to eq('true')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'returns true if testing a custom selector, and Unpoly requests "html"' do
|
56
|
+
request.headers['X-Up-Target'] = 'html'
|
57
|
+
get :up_is_target, tested_target: '.foo'
|
58
|
+
expect(response.body).to eq('true')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns true if testing "body", and Unpoly requests "html"' do
|
62
|
+
request.headers['X-Up-Target'] = 'html'
|
63
|
+
get :up_is_target, tested_target: 'body'
|
64
|
+
expect(response.body).to eq('true')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'returns true if testing "head", and Unpoly requests "html"' do
|
68
|
+
request.headers['X-Up-Target'] = 'html'
|
69
|
+
get :up_is_target, tested_target: 'head'
|
70
|
+
expect(response.body).to eq('true')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns false if the tested CSS selector is "head" but Unpoly requests "body"' do
|
74
|
+
request.headers['X-Up-Target'] = 'body'
|
75
|
+
get :up_is_target, tested_target: 'head'
|
76
|
+
expect(response.body).to eq('false')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'returns false if the tested CSS selector is "title" but Unpoly requests "body"' do
|
80
|
+
request.headers['X-Up-Target'] = 'body'
|
81
|
+
get :up_is_target, tested_target: 'title'
|
82
|
+
expect(response.body).to eq('false')
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns false if the tested CSS selector is "meta" but Unpoly requests "body"' do
|
86
|
+
request.headers['X-Up-Target'] = 'body'
|
87
|
+
get :up_is_target, tested_target: 'meta'
|
88
|
+
expect(response.body).to eq('false')
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns true if the tested CSS selector is "head", and Unpoly requests "html"' do
|
92
|
+
request.headers['X-Up-Target'] = 'html'
|
93
|
+
get :up_is_target, tested_target: 'head'
|
94
|
+
expect(response.body).to eq('true')
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'returns true if the tested CSS selector is "title", Unpoly requests "html"' do
|
98
|
+
request.headers['X-Up-Target'] = 'html'
|
99
|
+
get :up_is_target, tested_target: 'title'
|
100
|
+
expect(response.body).to eq('true')
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'returns true if the tested CSS selector is "meta", and Unpoly requests "html"' do
|
104
|
+
request.headers['X-Up-Target'] = 'html'
|
105
|
+
get :up_is_target, tested_target: 'meta'
|
106
|
+
expect(response.body).to eq('true')
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
30
111
|
describe '#validate?' do
|
31
112
|
|
32
113
|
it 'returns true the request is an Unpoly validation call' do
|
@@ -63,14 +144,4 @@ describe BindingTestController do
|
|
63
144
|
|
64
145
|
end
|
65
146
|
|
66
|
-
|
67
|
-
# describe '#test' do
|
68
|
-
#
|
69
|
-
# it 'does stuff' do
|
70
|
-
# get :test
|
71
|
-
# expect(response.body).to eq('foo')
|
72
|
-
# end
|
73
|
-
#
|
74
|
-
# end
|
75
|
-
|
76
147
|
end
|
@@ -47,6 +47,20 @@ describe 'up.flow', ->
|
|
47
47
|
expect(resolution).toHaveBeenCalled()
|
48
48
|
expect($('.middle')).toHaveText('new-middle')
|
49
49
|
|
50
|
+
it 'returns a promise that will be resolved once the server response was received and the swap animations have completed', (done) ->
|
51
|
+
resolution = jasmine.createSpy()
|
52
|
+
promise = up.replace('.middle', '/path', transition: 'cross-fade', duration: 50)
|
53
|
+
promise.then(resolution)
|
54
|
+
expect(resolution).not.toHaveBeenCalled()
|
55
|
+
expect($('.middle')).toHaveText('old-middle')
|
56
|
+
@respond()
|
57
|
+
expect(resolution).not.toHaveBeenCalled()
|
58
|
+
u.setTimer 20, ->
|
59
|
+
expect(resolution).not.toHaveBeenCalled()
|
60
|
+
u.setTimer 80, ->
|
61
|
+
expect(resolution).toHaveBeenCalled()
|
62
|
+
done()
|
63
|
+
|
50
64
|
describe 'with { data } option', ->
|
51
65
|
|
52
66
|
it "uses the given params as a non-GET request's payload", ->
|
@@ -470,19 +484,19 @@ describe 'up.flow', ->
|
|
470
484
|
|
471
485
|
it 'morphs between the old and new element', (done) ->
|
472
486
|
affix('.element').text('version 1')
|
473
|
-
up.extract('.element', '<div class="element">version 2</div>', transition: 'cross-fade', duration:
|
487
|
+
up.extract('.element', '<div class="element">version 2</div>', transition: 'cross-fade', duration: 200)
|
474
488
|
|
475
489
|
$ghost1 = $('.element.up-ghost:contains("version 1")')
|
476
490
|
expect($ghost1).toHaveLength(1)
|
477
|
-
expect($ghost1
|
491
|
+
expect(u.opacity($ghost1)).toBeAround(1.0, 0.1)
|
478
492
|
|
479
493
|
$ghost2 = $('.element.up-ghost:contains("version 2")')
|
480
494
|
expect($ghost2).toHaveLength(1)
|
481
|
-
expect($ghost2
|
495
|
+
expect(u.opacity($ghost2)).toBeAround(0.0, 0.1)
|
482
496
|
|
483
|
-
u.setTimer
|
484
|
-
expect($ghost1
|
485
|
-
expect($ghost2
|
497
|
+
u.setTimer 190, ->
|
498
|
+
expect(u.opacity($ghost1)).toBeAround(0.0, 0.3)
|
499
|
+
expect(u.opacity($ghost2)).toBeAround(1.0, 0.3)
|
486
500
|
done()
|
487
501
|
|
488
502
|
it 'marks the old fragment and its ghost as .up-destroying during the transition', ->
|
@@ -534,7 +548,7 @@ describe 'up.flow', ->
|
|
534
548
|
promise = up.extract('.element', '<div class="element">version 2</div>', transition: 'cross-fade', duration: 30)
|
535
549
|
promise.then(resolution)
|
536
550
|
expect(resolution).not.toHaveBeenCalled()
|
537
|
-
u.setTimer
|
551
|
+
u.setTimer 70, ->
|
538
552
|
expect(resolution).toHaveBeenCalled()
|
539
553
|
done()
|
540
554
|
|
@@ -215,6 +215,21 @@ describe 'up.form', ->
|
|
215
215
|
expect(submitSpy).toHaveBeenCalled()
|
216
216
|
done()
|
217
217
|
|
218
|
+
it 'marks the field with an .up-active class while the form is submitting', (done) ->
|
219
|
+
$form = affix('form')
|
220
|
+
$field = $form.affix('input[up-autosubmit][val="old-value"]')
|
221
|
+
up.hello($field)
|
222
|
+
submission = $.Deferred()
|
223
|
+
submitSpy = up.form.knife.mock('submit').and.returnValue(submission)
|
224
|
+
$field.val('new-value')
|
225
|
+
$field.trigger('change')
|
226
|
+
u.nextFrame ->
|
227
|
+
expect(submitSpy).toHaveBeenCalled()
|
228
|
+
expect($field).toHaveClass('up-active')
|
229
|
+
submission.resolve()
|
230
|
+
expect($field).not.toHaveClass('up-active')
|
231
|
+
done()
|
232
|
+
|
218
233
|
describe 'form[up-autosubmit]', ->
|
219
234
|
|
220
235
|
it 'submits the form when a change is observed in any of its fields', (done) ->
|
@@ -44,6 +44,8 @@ describe 'up.link', ->
|
|
44
44
|
|
45
45
|
it 'adds history entries and allows the user to use the back- and forward-buttons', (done) ->
|
46
46
|
|
47
|
+
waitForBrowser = 70
|
48
|
+
|
47
49
|
# By default, up.history will replace the <body> tag when
|
48
50
|
# the user presses the back-button. We reconfigure this
|
49
51
|
# so we don't lose the Jasmine runner interface.
|
@@ -83,21 +85,21 @@ describe 'up.link', ->
|
|
83
85
|
expect(document.title).toEqual('title from three')
|
84
86
|
|
85
87
|
history.back()
|
86
|
-
u.setTimer
|
88
|
+
u.setTimer waitForBrowser, ->
|
87
89
|
respondWith('restored text from two', 'restored title from two')
|
88
90
|
expect($('.target')).toHaveText('restored text from two')
|
89
91
|
expect(location.pathname).toEqual('/two')
|
90
92
|
expect(document.title).toEqual('restored title from two')
|
91
93
|
|
92
94
|
history.back()
|
93
|
-
u.setTimer
|
95
|
+
u.setTimer waitForBrowser, ->
|
94
96
|
respondWith('restored text from one', 'restored title from one')
|
95
97
|
expect($('.target')).toHaveText('restored text from one')
|
96
98
|
expect(location.pathname).toEqual('/one')
|
97
99
|
expect(document.title).toEqual('restored title from one')
|
98
100
|
|
99
101
|
history.forward()
|
100
|
-
u.setTimer
|
102
|
+
u.setTimer waitForBrowser, ->
|
101
103
|
# Since the response is cached, we don't have to respond
|
102
104
|
expect($('.target')).toHaveText('restored text from two', 'restored title from two')
|
103
105
|
expect(location.pathname).toEqual('/two')
|
@@ -367,7 +369,7 @@ describe 'up.link', ->
|
|
367
369
|
|
368
370
|
it 'morphs between the old and new target element', (done) ->
|
369
371
|
affix('.target.old')
|
370
|
-
$link = affix('a[href="/path"][up-target=".target"][up-transition="cross-fade"][up-duration="
|
372
|
+
$link = affix('a[href="/path"][up-target=".target"][up-transition="cross-fade"][up-duration="300"][up-easing="linear"]')
|
371
373
|
$link.click()
|
372
374
|
@respondWith '<div class="target new">new text</div>'
|
373
375
|
|
@@ -375,12 +377,11 @@ describe 'up.link', ->
|
|
375
377
|
$newGhost = $('.target.new.up-ghost')
|
376
378
|
expect($oldGhost).toExist()
|
377
379
|
expect($newGhost).toExist()
|
378
|
-
opacity
|
379
|
-
expect(opacity($
|
380
|
-
|
381
|
-
|
382
|
-
expect(opacity($
|
383
|
-
expect(opacity($newGhost)).toBeAround(0.5, 0.15)
|
380
|
+
expect(u.opacity($oldGhost)).toBeAround(1, 0.15)
|
381
|
+
expect(u.opacity($newGhost)).toBeAround(0, 0.15)
|
382
|
+
u.setTimer 150, ->
|
383
|
+
expect(u.opacity($oldGhost)).toBeAround(0.5, 0.15)
|
384
|
+
expect(u.opacity($newGhost)).toBeAround(0.5, 0.15)
|
384
385
|
done()
|
385
386
|
|
386
387
|
it 'does not add a history entry when an up-history attribute is set to "false"', ->
|