unpoly-rails 0.53.1 → 0.53.2
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 +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)
|