unpoly-rails 0.53.1 → 0.53.2
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 +17 -1
- data/dist/unpoly.js +65 -19
- data/dist/unpoly.min.js +4 -4
- data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +2 -2
- data/lib/assets/javascripts/unpoly/dom.coffee +2 -0
- data/lib/assets/javascripts/unpoly/form.coffee +2 -2
- data/lib/assets/javascripts/unpoly/layout.coffee +2 -1
- data/lib/assets/javascripts/unpoly/modal.coffee +3 -0
- data/lib/assets/javascripts/unpoly/motion.coffee +10 -2
- data/lib/assets/javascripts/unpoly/proxy.coffee +17 -8
- data/lib/assets/javascripts/unpoly/util.coffee +23 -0
- data/lib/unpoly/rails/version.rb +1 -1
- data/package.json +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/app/controllers/form_test/basics_controller.rb +1 -1
- data/spec_app/app/views/reveal_test/long1.erb +6 -1
- data/spec_app/app/views/reveal_test/long2.erb +6 -1
- data/spec_app/spec/javascripts/helpers/to_have_unhandled_rejections.coffee +36 -0
- data/spec_app/spec/javascripts/helpers/trigger.js.coffee +30 -0
- data/spec_app/spec/javascripts/up/dom_spec.js.coffee +1 -1
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +78 -7
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +17 -0
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +98 -4
- data/spec_app/spec/javascripts/up/radio_spec.js.coffee +2 -0
- metadata +3 -2
data/lib/unpoly/rails/version.rb
CHANGED
data/package.json
CHANGED
data/spec_app/Gemfile.lock
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
<script>
|
2
|
+
up.motion.config.duration = 2000
|
3
|
+
up.layout.config.duration = 2000
|
4
|
+
</script>
|
5
|
+
|
1
6
|
<div class="long-page" style="height: 2000px; background-color: rgba(0, 0, 255, 0.3)">
|
2
7
|
|
3
8
|
<h2>Long page 1</h2>
|
4
9
|
|
5
|
-
<ul>
|
10
|
+
<ul style="margin-top: 200px">
|
6
11
|
<li><a up-target=".long-page" href="long2" up-reveal="true" up-transition="false" >Go to long page 2 (with reveal, without animation)</a></li>
|
7
12
|
<li><a up-target=".long-page" href="long2" up-reveal="true" up-transition="cross-fade">Go to long page 2 (with reveal, with animation) </a></li>
|
8
13
|
<li><a up-target=".long-page" href="long2" up-reveal="false" up-transition="false" >Go to long page 2 (without reveal, without animation)</a></li>
|
@@ -1,8 +1,13 @@
|
|
1
|
+
<script>
|
2
|
+
up.motion.config.duration = 2000
|
3
|
+
up.layout.config.duration = 2000
|
4
|
+
</script>
|
5
|
+
|
1
6
|
<div class="long-page" style="height: 2000px; background-color: rgba(255, 0, 0, 0.3)">
|
2
7
|
|
3
8
|
<h2>Long page 2</h2>
|
4
9
|
|
5
|
-
<ul>
|
10
|
+
<ul style="margin-top: 200px">
|
6
11
|
<li><a up-target=".long-page" href="long1" up-reveal="true" up-transition="false" >Go to long page 1 (with reveal, without animation)</a></li>
|
7
12
|
<li><a up-target=".long-page" href="long1" up-reveal="true" up-transition="cross-fade">Go to long page 1 (with reveal, with animation) </a></li>
|
8
13
|
<li><a up-target=".long-page" href="long1" up-reveal="false" up-transition="false" >Go to long page 1 (without reveal, without animation)</a></li>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
UNHANDLED_REJECTIONS = []
|
2
|
+
|
3
|
+
beforeAll ->
|
4
|
+
window.addEventListener 'unhandledrejection', (event) ->
|
5
|
+
UNHANDLED_REJECTIONS.push(event)
|
6
|
+
|
7
|
+
beforeEach ->
|
8
|
+
UNHANDLED_REJECTIONS = []
|
9
|
+
|
10
|
+
jasmine.addMatchers
|
11
|
+
toHaveUnhandledRejections: (util, customEqualityTesters) ->
|
12
|
+
compare: (actual) ->
|
13
|
+
# It doesn't really matter what's in actual.
|
14
|
+
# A good way to call this is e.g. `expect(window).not.toHaveUnhandledRejections()
|
15
|
+
pass: UNHANDLED_REJECTIONS.length > 0
|
16
|
+
|
17
|
+
#UnhandledRejectionTracker = do ->
|
18
|
+
#
|
19
|
+
#
|
20
|
+
#
|
21
|
+
#
|
22
|
+
#
|
23
|
+
##beforeEach (done) ->
|
24
|
+
## @unhandledRejections = []
|
25
|
+
## @trackUnhandledRejections = (event) =>
|
26
|
+
## @unhandledRejections.push(event)
|
27
|
+
## window.addEventListener('unhandledrejection', @trackUnhandledRejections)
|
28
|
+
## done()
|
29
|
+
##
|
30
|
+
##afterEach (done) ->
|
31
|
+
## hadUnhandledRejections = @unhandledRejections.length > 0
|
32
|
+
## @unhandledRejections = []
|
33
|
+
## if hadUnhandledRejections
|
34
|
+
## done.fail('There were rejected promises without a rejection handler')
|
35
|
+
## else
|
36
|
+
## done()
|
@@ -7,11 +7,26 @@
|
|
7
7
|
event = createMouseEvent('mouseover', options)
|
8
8
|
dispatch($element, event)
|
9
9
|
|
10
|
+
mouseenter = (element, options) ->
|
11
|
+
$element = $(element)
|
12
|
+
event = createMouseEvent('mouseenter', options)
|
13
|
+
dispatch($element, event)
|
14
|
+
|
10
15
|
mousedown = (element, options) ->
|
11
16
|
$element = $(element)
|
12
17
|
event = createMouseEvent('mousedown', options)
|
13
18
|
dispatch($element, event)
|
14
19
|
|
20
|
+
mouseout = (element, options) ->
|
21
|
+
$element = $(element)
|
22
|
+
event = createMouseEvent('mouseout', options)
|
23
|
+
dispatch($element, event)
|
24
|
+
|
25
|
+
mouseleave = (element, options) ->
|
26
|
+
$element = $(element)
|
27
|
+
event = createMouseEvent('mouseleave', options)
|
28
|
+
dispatch($element, event)
|
29
|
+
|
15
30
|
mouseup = (element, options) ->
|
16
31
|
$element = $(element)
|
17
32
|
event = createMouseEvent('mouseup', options)
|
@@ -34,6 +49,16 @@
|
|
34
49
|
mouseup($element, options)
|
35
50
|
click($element, options)
|
36
51
|
|
52
|
+
hoverSequence = (element, options) ->
|
53
|
+
$element = $(element)
|
54
|
+
mouseover($element, options)
|
55
|
+
mouseenter($element, options)
|
56
|
+
|
57
|
+
unhoverSequence = (element, options) ->
|
58
|
+
$element = $(element)
|
59
|
+
mouseout($element, options)
|
60
|
+
mouseleave($element, options)
|
61
|
+
|
37
62
|
# Can't use the new MouseEvent constructor in IE11 because computer.
|
38
63
|
# http://www.codeproject.com/Tips/893254/JavaScript-Triggering-Event-Manually-in-Internet-E
|
39
64
|
createMouseEvent = (type, options) ->
|
@@ -77,10 +102,15 @@
|
|
77
102
|
this.dispatchEvent(event)
|
78
103
|
|
79
104
|
mouseover: mouseover
|
105
|
+
mouseenter: mouseenter
|
80
106
|
mousedown: mousedown
|
81
107
|
mouseup: mouseup
|
108
|
+
mouseout: mouseout
|
109
|
+
mouseleave: mouseleave
|
82
110
|
click: click
|
83
111
|
clickSequence: clickSequence
|
112
|
+
hoverSequence: hoverSequence
|
113
|
+
unhoverSequence: unhoverSequence
|
84
114
|
createMouseEvent: createMouseEvent
|
85
115
|
|
86
116
|
)()
|
@@ -940,7 +940,7 @@ describe 'up.dom', ->
|
|
940
940
|
|
941
941
|
next =>
|
942
942
|
expect(@revealedHTML).toEqual ['<div id="three">three</div>']
|
943
|
-
expect(@revealOptions).toEqual
|
943
|
+
expect(@revealOptions).toEqual jasmine.objectContaining(top: true)
|
944
944
|
|
945
945
|
it "reveals the entire element if it has no child with the ID of that #hash", asyncSpec (next) ->
|
946
946
|
up.replace('.middle', '/path#four', reveal: true)
|
@@ -355,6 +355,8 @@ describe 'up.form', ->
|
|
355
355
|
expect('.before').not.toHaveText('old-before')
|
356
356
|
expect('.after').not.toHaveText('old-after')
|
357
357
|
|
358
|
+
expect(window).toHaveUnhandledRejections()
|
359
|
+
|
358
360
|
it 'respects X-Up-Method and X-Up-Location response headers so the server can show that it redirected to a GET URL', asyncSpec (next) ->
|
359
361
|
up.submit(@$form)
|
360
362
|
|
@@ -529,7 +531,70 @@ describe 'up.form', ->
|
|
529
531
|
|
530
532
|
describe 'form[up-target]', ->
|
531
533
|
|
532
|
-
it '
|
534
|
+
it 'submits the form with AJAX and replaces the [up-target] selector', asyncSpec (next) ->
|
535
|
+
up.history.config.enabled = true
|
536
|
+
|
537
|
+
affix('.response').text('old text')
|
538
|
+
|
539
|
+
$form = affix('form[action="/form-target"][method="put"][up-target=".response"]')
|
540
|
+
$form.append('<input name="field1" value="value1">')
|
541
|
+
$form.append('<input name="field2" value="value2">')
|
542
|
+
$submitButton = $form.affix('input[type="submit"][name="submit-button"][value="submit-button-value"]')
|
543
|
+
up.hello($form)
|
544
|
+
|
545
|
+
Trigger.clickSequence($submitButton)
|
546
|
+
|
547
|
+
next =>
|
548
|
+
params = @lastRequest().data()
|
549
|
+
expect(params['field1']).toEqual(['value1'])
|
550
|
+
expect(params['field2']).toEqual(['value2'])
|
551
|
+
|
552
|
+
next =>
|
553
|
+
@respondWith """
|
554
|
+
<div class="response">
|
555
|
+
new text
|
556
|
+
</div>
|
557
|
+
"""
|
558
|
+
|
559
|
+
next =>
|
560
|
+
expect('.response').toHaveText('new text')
|
561
|
+
|
562
|
+
describe 'when the server responds with an error code', ->
|
563
|
+
|
564
|
+
it 'replaces the form instead of the [up-target] selector', asyncSpec (next) ->
|
565
|
+
up.history.config.enabled = true
|
566
|
+
|
567
|
+
affix('.response').text('old text')
|
568
|
+
|
569
|
+
$form = affix('form.test-form[action="/form-target"][method="put"][up-target=".response"]')
|
570
|
+
$form.append('<input name="field1" value="value1">')
|
571
|
+
$form.append('<input name="field2" value="value2">')
|
572
|
+
$submitButton = $form.affix('input[type="submit"][name="submit-button"][value="submit-button-value"]')
|
573
|
+
up.hello($form)
|
574
|
+
|
575
|
+
Trigger.clickSequence($submitButton)
|
576
|
+
|
577
|
+
next =>
|
578
|
+
params = @lastRequest().data()
|
579
|
+
expect(params['field1']).toEqual(['value1'])
|
580
|
+
expect(params['field2']).toEqual(['value2'])
|
581
|
+
|
582
|
+
next =>
|
583
|
+
@respondWith
|
584
|
+
status: 500
|
585
|
+
responseText: """
|
586
|
+
<form class="test-form">
|
587
|
+
validation errors
|
588
|
+
</form>
|
589
|
+
"""
|
590
|
+
|
591
|
+
next =>
|
592
|
+
expect('.response').toHaveText('old text')
|
593
|
+
expect('form.test-form').toHaveText('validation errors')
|
594
|
+
|
595
|
+
# Since there isn't anyone who could handle the rejection inside
|
596
|
+
# the event handler, our handler mutes the rejection.
|
597
|
+
expect(window).not.toHaveUnhandledRejections()
|
533
598
|
|
534
599
|
describe 'submit buttons', ->
|
535
600
|
|
@@ -711,12 +776,14 @@ describe 'up.form', ->
|
|
711
776
|
expect(request.requestHeaders['X-Up-Validate']).toEqual('user')
|
712
777
|
expect(request.requestHeaders['X-Up-Target']).toEqual('.field-group:has(input[name="user"])')
|
713
778
|
|
714
|
-
@respondWith
|
715
|
-
|
716
|
-
|
717
|
-
<
|
718
|
-
|
719
|
-
|
779
|
+
@respondWith
|
780
|
+
status: 500
|
781
|
+
responseText: """
|
782
|
+
<div class="field-group has-error">
|
783
|
+
<div class='error'>Username has already been taken</div>
|
784
|
+
<input name="user" value="judy" up-validate=".field-group:has(&)">
|
785
|
+
</div>
|
786
|
+
"""
|
720
787
|
|
721
788
|
next =>
|
722
789
|
$group = $('.field-group')
|
@@ -724,6 +791,10 @@ describe 'up.form', ->
|
|
724
791
|
expect($group).toHaveClass('has-error')
|
725
792
|
expect($group).toHaveText('Username has already been taken')
|
726
793
|
|
794
|
+
# Since there isn't anyone who could handle the rejection inside
|
795
|
+
# the event handler, our handler mutes the rejection.
|
796
|
+
expect(window).not.toHaveUnhandledRejections()
|
797
|
+
|
727
798
|
it 'does not reveal the updated fragment (bugfix)', asyncSpec (next) ->
|
728
799
|
revealSpy = up.layout.knife.mock('reveal').and.returnValue(Promise.resolve())
|
729
800
|
|
@@ -654,6 +654,18 @@ describe 'up.link', ->
|
|
654
654
|
|
655
655
|
describeCapability 'canPushState', ->
|
656
656
|
|
657
|
+
it 'requests the [href] with AJAX and replaces the [up-target] selector', asyncSpec (next) ->
|
658
|
+
affix('.target')
|
659
|
+
$link = affix('a[href="/path"][up-target=".target"]')
|
660
|
+
Trigger.clickSequence($link)
|
661
|
+
|
662
|
+
next =>
|
663
|
+
@respondWith('<div class="target">new text</div>')
|
664
|
+
|
665
|
+
next =>
|
666
|
+
expect($('.target')).toHaveText('new text')
|
667
|
+
|
668
|
+
|
657
669
|
it 'adds a history entry', asyncSpec (next) ->
|
658
670
|
up.history.config.enabled = true
|
659
671
|
|
@@ -784,6 +796,11 @@ describe 'up.link', ->
|
|
784
796
|
expect($('.success-target')).toHaveText('old success text')
|
785
797
|
expect($('.failure-target')).toHaveText('new failure text')
|
786
798
|
|
799
|
+
# Since there isn't anyone who could handle the rejection inside
|
800
|
+
# the event handler, our handler mutes the rejection.
|
801
|
+
expect(window).not.toHaveUnhandledRejections()
|
802
|
+
|
803
|
+
|
787
804
|
it 'uses the [up-target] selector for a successful response', asyncSpec (next) ->
|
788
805
|
Trigger.clickSequence(@$link)
|
789
806
|
|
@@ -973,25 +973,119 @@ describe 'up.proxy', ->
|
|
973
973
|
|
974
974
|
describe '[up-preload]', ->
|
975
975
|
|
976
|
-
it 'preloads the link destination
|
976
|
+
it 'preloads the link destination when hovering, after a delay', asyncSpec (next) ->
|
977
|
+
up.proxy.config.preloadDelay = 100
|
978
|
+
|
979
|
+
affix('.target').text('old text')
|
980
|
+
|
981
|
+
$link = affix('a[href="/foo"][up-target=".target"][up-preload]')
|
982
|
+
up.hello($link)
|
983
|
+
|
984
|
+
Trigger.hoverSequence($link)
|
985
|
+
|
986
|
+
next.after 50, =>
|
987
|
+
# It's still too early
|
988
|
+
expect(jasmine.Ajax.requests.count()).toEqual(0)
|
989
|
+
|
990
|
+
next.after 75, =>
|
991
|
+
expect(jasmine.Ajax.requests.count()).toEqual(1)
|
992
|
+
expect(@lastRequest().url).toMatchUrl('/foo')
|
993
|
+
expect(@lastRequest()).toHaveRequestMethod('GET')
|
994
|
+
expect(@lastRequest().requestHeaders['X-Up-Target']).toEqual('.target')
|
995
|
+
|
996
|
+
@respondWith """
|
997
|
+
<div class="target">
|
998
|
+
new text
|
999
|
+
</div>
|
1000
|
+
"""
|
1001
|
+
|
1002
|
+
next =>
|
1003
|
+
# We only preloaded, so the target isn't replaced yet.
|
1004
|
+
expect('.target').toHaveText('old text')
|
1005
|
+
|
1006
|
+
Trigger.clickSequence($link)
|
1007
|
+
|
1008
|
+
next =>
|
1009
|
+
# No additional request has been sent since we already preloaded
|
1010
|
+
expect(jasmine.Ajax.requests.count()).toEqual(1)
|
1011
|
+
|
1012
|
+
# The target is replaced instantly
|
1013
|
+
expect('.target').toHaveText('new text')
|
1014
|
+
|
1015
|
+
it 'does not send a request if the user stops hovering before the delay is over', asyncSpec (next) ->
|
1016
|
+
up.proxy.config.preloadDelay = 100
|
1017
|
+
|
1018
|
+
affix('.target').text('old text')
|
1019
|
+
|
1020
|
+
$link = affix('a[href="/foo"][up-target=".target"][up-preload]')
|
1021
|
+
up.hello($link)
|
1022
|
+
|
1023
|
+
Trigger.hoverSequence($link)
|
1024
|
+
|
1025
|
+
next.after 40, =>
|
1026
|
+
# It's still too early
|
1027
|
+
expect(jasmine.Ajax.requests.count()).toEqual(0)
|
1028
|
+
|
1029
|
+
Trigger.unhoverSequence($link)
|
1030
|
+
|
1031
|
+
next.after 90, =>
|
1032
|
+
expect(jasmine.Ajax.requests.count()).toEqual(0)
|
1033
|
+
|
1034
|
+
it 'does not cache a failed response', asyncSpec (next) ->
|
1035
|
+
up.proxy.config.preloadDelay = 0
|
1036
|
+
|
1037
|
+
affix('.target').text('old text')
|
1038
|
+
|
1039
|
+
$link = affix('a[href="/foo"][up-target=".target"][up-preload]')
|
1040
|
+
up.hello($link)
|
1041
|
+
|
1042
|
+
Trigger.hoverSequence($link)
|
1043
|
+
|
1044
|
+
next.after 2, =>
|
1045
|
+
expect(jasmine.Ajax.requests.count()).toEqual(1)
|
1046
|
+
|
1047
|
+
@respondWith
|
1048
|
+
status: 500
|
1049
|
+
responseText: """
|
1050
|
+
<div class="target">
|
1051
|
+
new text
|
1052
|
+
</div>
|
1053
|
+
"""
|
1054
|
+
|
1055
|
+
next =>
|
1056
|
+
# We only preloaded, so the target isn't replaced yet.
|
1057
|
+
expect('.target').toHaveText('old text')
|
1058
|
+
|
1059
|
+
Trigger.click($link)
|
1060
|
+
|
1061
|
+
next =>
|
1062
|
+
# Since the preloading failed, we send another request
|
1063
|
+
expect(jasmine.Ajax.requests.count()).toEqual(2)
|
1064
|
+
|
1065
|
+
# Since there isn't anyone who could handle the rejection inside
|
1066
|
+
# the event handler, our handler mutes the rejection.
|
1067
|
+
expect(window).not.toHaveUnhandledRejections()
|
977
1068
|
|
978
1069
|
it 'triggers a separate AJAX request when hovered multiple times and the cache expires between hovers', asyncSpec (next) ->
|
979
1070
|
up.proxy.config.cacheExpiry = 50
|
980
1071
|
up.proxy.config.preloadDelay = 0
|
1072
|
+
|
981
1073
|
$element = affix('a[href="/foo"][up-preload]')
|
982
|
-
|
1074
|
+
up.hello($element)
|
1075
|
+
|
1076
|
+
Trigger.hoverSequence($element)
|
983
1077
|
|
984
1078
|
next.after 1, =>
|
985
1079
|
expect(jasmine.Ajax.requests.count()).toEqual(1)
|
986
1080
|
|
987
1081
|
next.after 1, =>
|
988
|
-
Trigger.
|
1082
|
+
Trigger.hoverSequence($element)
|
989
1083
|
|
990
1084
|
next.after 1, =>
|
991
1085
|
expect(jasmine.Ajax.requests.count()).toEqual(1)
|
992
1086
|
|
993
1087
|
next.after 60, =>
|
994
|
-
Trigger.
|
1088
|
+
Trigger.hoverSequence($element)
|
995
1089
|
|
996
1090
|
next.after 1, =>
|
997
1091
|
expect(jasmine.Ajax.requests.count()).toEqual(2)
|