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.

@@ -4,6 +4,6 @@ module Unpoly
4
4
  # The current version of the unpoly-rails gem.
5
5
  # This version number is also used for releases of the Unpoly
6
6
  # frontend code.
7
- VERSION = '0.53.1'
7
+ VERSION = '0.53.2'
8
8
  end
9
9
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unpoly",
3
- "version": "0.53.1",
3
+ "version": "0.53.2",
4
4
  "description": "Unobtrusive JavaScript framework",
5
5
  "main": "dist/unpoly.js",
6
6
  "files": [
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- unpoly-rails (0.53.0)
4
+ unpoly-rails (0.53.1)
5
5
  rails (>= 3)
6
6
 
7
7
  GEM
@@ -7,7 +7,7 @@ module FormTest
7
7
  end
8
8
 
9
9
  def create
10
- render 'form_test/submission_result'
10
+ render 'form_test/submission_result', status: 500
11
11
  end
12
12
 
13
13
  end
@@ -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 { top: true }
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 'rigs the form to use up.submit instead of a standard submit'
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
- <div class="field-group has-error">
716
- <div class='error'>Username has already been taken</div>
717
- <input name="user" value="judy" up-validate=".field-group:has(&)">
718
- </div>
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 on mouseover, after a delay'
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
- Trigger.mouseover($element)
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.mouseover($element)
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.mouseover($element)
1088
+ Trigger.hoverSequence($element)
995
1089
 
996
1090
  next.after 1, =>
997
1091
  expect(jasmine.Ajax.requests.count()).toEqual(2)
@@ -1,5 +1,7 @@
1
1
  describe 'up.radio', ->
2
2
 
3
+ u = up.util
4
+
3
5
  describe 'JavaScript functions', ->
4
6
 
5
7
  describe 'unobtrusive behavior', ->