unpoly-rails 0.23.0 → 0.24.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.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -0
  3. data/dist/unpoly-bootstrap3.js +1 -1
  4. data/dist/unpoly-bootstrap3.min.js +1 -1
  5. data/dist/unpoly.css +18 -8
  6. data/dist/unpoly.js +498 -265
  7. data/dist/unpoly.min.css +1 -1
  8. data/dist/unpoly.min.js +3 -3
  9. data/lib/assets/javascripts/unpoly-bootstrap3/modal-ext.js.coffee +5 -2
  10. data/lib/assets/javascripts/unpoly/flow.js.coffee +3 -1
  11. data/lib/assets/javascripts/unpoly/form.js.coffee +3 -6
  12. data/lib/assets/javascripts/unpoly/layout.js.coffee +1 -1
  13. data/lib/assets/javascripts/unpoly/link.js.coffee +4 -2
  14. data/lib/assets/javascripts/unpoly/log.js.coffee +2 -2
  15. data/lib/assets/javascripts/unpoly/modal.js.coffee +125 -36
  16. data/lib/assets/javascripts/unpoly/motion.js.coffee +75 -37
  17. data/lib/assets/javascripts/unpoly/navigation.js.coffee +38 -26
  18. data/lib/assets/javascripts/unpoly/proxy.js.coffee +77 -52
  19. data/lib/assets/javascripts/unpoly/syntax.js.coffee +1 -0
  20. data/lib/assets/javascripts/unpoly/tooltip.js.coffee +2 -0
  21. data/lib/assets/javascripts/unpoly/util.js.coffee +138 -46
  22. data/lib/assets/stylesheets/unpoly/link.css.sass +1 -1
  23. data/lib/assets/stylesheets/unpoly/modal.css.sass +28 -15
  24. data/lib/unpoly/rails/version.rb +1 -1
  25. data/spec_app/Gemfile.lock +7 -7
  26. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +2 -0
  27. data/spec_app/spec/javascripts/helpers/to_contain.js.coffee +5 -0
  28. data/spec_app/spec/javascripts/up/flow_spec.js.coffee +2 -2
  29. data/spec_app/spec/javascripts/up/history_spec.js.coffee +6 -4
  30. data/spec_app/spec/javascripts/up/link_spec.js.coffee +114 -5
  31. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +28 -18
  32. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +112 -7
  33. data/spec_app/spec/javascripts/up/navigation_spec.js.coffee +157 -121
  34. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +1 -1
  35. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +42 -3
  36. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +1 -2
  37. data/spec_app/spec/javascripts/up/util_spec.js.coffee +26 -1
  38. data/spec_app/vendor/assets/bower_components/jquery/.bower.json +1 -1
  39. metadata +3 -3
  40. data/spec_app/spec/javascripts/helpers/set_timer.js.coffee +0 -3
@@ -1,2 +1,2 @@
1
- [up-href][up-follow], [up-href][up-target]
1
+ [up-href]
2
2
  cursor: pointer
@@ -1,35 +1,50 @@
1
- $stratum: 10000
2
- $substratum-dialog: 1000
3
- $substratum-content: 2000
4
- $substratum-close: 3000
1
+ $stratum-backdrop: 10000
2
+ $stratum-elements: 11000
3
+
4
+ // These could actually be 1000, 2000, 3000 and 4000 since the `fixed` position of some elements defines
5
+ // a stacking context for all contained z-indexes.
6
+ //
7
+ // However, let's keep the option open that these elements will one day not have its stacking context.
8
+ //
9
+ // Also let's not do 1, 2, 3 and 4 so other elements have a chance to move themselves between the layers.
10
+ $substratum-dialog: 12000
11
+ $substratum-content: 13000
12
+ $substratum-close: 14000
5
13
 
6
14
  $close-height: 36px
7
15
  $close-width: 36px
8
16
  $close-font-size: 34px
9
17
 
10
- =transform($transform)
11
- transform: $transform
12
- -ms-transform: $transform // IE9
13
- -webkit-transform: $transform // Safari, Some Android
14
-
15
18
  .up-modal
19
+
20
+ .up-modal-backdrop
21
+ z-index: $stratum-backdrop
22
+ background-color: rgba(90, 90, 90, 0.4)
23
+ position: fixed
24
+ top: 0
25
+ right: 0
26
+ bottom: 0
27
+ left: 0
28
+
29
+ .up-modal-viewport
30
+ z-index: $stratum-elements
16
31
  position: fixed
17
32
  top: 0
18
33
  left: 0
19
34
  bottom: 0
20
35
  right: 0
21
- z-index: $stratum
22
- background-color: rgba(90, 90, 90, 0.4)
23
36
  overflow-x: hidden
24
- overflow-y: scroll
37
+ overflow-y: hidden
25
38
  // We prefer centering the dialog as an `inline-block`
26
39
  // to giving it a horizontal margin of `auto`. This way
27
40
  // the width of `.up-modal-dialog` is controlled by the
28
41
  // contents of `.up-modal-content`.
29
42
  text-align: center
30
43
 
44
+ .up-modal.up-modal-ready &
45
+ overflow-y: scroll
46
+
31
47
  .up-modal-dialog
32
- // The z-index lives in the stacking context of .up-modal
33
48
  z-index: $substratum-dialog
34
49
  // Make sure .up-modal-close is relative to the dialog
35
50
  position: relative
@@ -47,14 +62,12 @@ $close-font-size: 34px
47
62
  text-align: left
48
63
 
49
64
  .up-modal-content
50
- // The z-index lives in the stacking context of .up-modal
51
65
  z-index: $substratum-content
52
66
  padding: 20px
53
67
  background-color: #fff
54
68
  box-shadow: 0 0 10px 1px rgba(0, 0, 0, 0.3)
55
69
 
56
70
  .up-modal-close
57
- // The z-index lives in the stacking context of .up-modal
58
71
  z-index: $substratum-close
59
72
  position: absolute
60
73
  right: 0
@@ -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.23.0'
7
+ VERSION = '0.24.0'
8
8
  end
9
9
  end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- unpoly-rails (0.22.1)
4
+ unpoly-rails (0.23.1)
5
5
  rails (>= 3)
6
6
 
7
7
  GEM
@@ -88,8 +88,8 @@ GEM
88
88
  phantomjs (>= 1.9)
89
89
  railties (>= 3.2.0)
90
90
  sprockets-rails
91
- jquery-rails (4.0.2)
92
- rails-dom-testing (~> 1.0)
91
+ jquery-rails (4.1.1)
92
+ rails-dom-testing (>= 1, < 3)
93
93
  railties (>= 4.2.0)
94
94
  thor (>= 0.14, < 2.0)
95
95
  json (1.8.3)
@@ -100,9 +100,9 @@ GEM
100
100
  mime-types (>= 1.16, < 3)
101
101
  mime-types (2.99)
102
102
  mini_portile2 (2.0.0)
103
- minitest (5.8.3)
103
+ minitest (5.8.4)
104
104
  multi_json (1.11.2)
105
- nokogiri (1.6.7.1)
105
+ nokogiri (1.6.7.2)
106
106
  mini_portile2 (~> 2.0.0.rc2)
107
107
  phantomjs (1.9.8.0)
108
108
  rack (1.6.4)
@@ -125,14 +125,14 @@ GEM
125
125
  activesupport (>= 4.2.0.beta, < 5.0)
126
126
  nokogiri (~> 1.6.0)
127
127
  rails-deprecated_sanitizer (>= 1.0.1)
128
- rails-html-sanitizer (1.0.2)
128
+ rails-html-sanitizer (1.0.3)
129
129
  loofah (~> 2.0)
130
130
  railties (4.2.0)
131
131
  actionpack (= 4.2.0)
132
132
  activesupport (= 4.2.0)
133
133
  rake (>= 0.8.7)
134
134
  thor (>= 0.18.1, < 2.0)
135
- rake (10.4.2)
135
+ rake (11.1.2)
136
136
  ref (1.0.5)
137
137
  rspec-core (3.4.1)
138
138
  rspec-support (~> 3.4.0)
@@ -1,4 +1,6 @@
1
1
  afterEach ->
2
+ console.debug('--- Resetting Unpoly after example ---')
3
+ up.motion.finish()
2
4
  up.reset()
3
5
  $('.up-error').remove()
4
6
  console.debug('--- Unpoly was reset after example ---')
@@ -0,0 +1,5 @@
1
+ beforeEach ->
2
+ jasmine.addMatchers
3
+ toContain: (util, customEqualityTesters) ->
4
+ compare: (object, expectedElement) ->
5
+ pass: up.util.contains(object, expectedElement)
@@ -480,7 +480,7 @@ describe 'up.flow', ->
480
480
  expect($ghost2).toHaveLength(1)
481
481
  expect($ghost2.css('opacity')).toBeAround(0.0, 0.1)
482
482
 
483
- @setTimer 40, ->
483
+ u.setTimer 40, ->
484
484
  expect($ghost1.css('opacity')).toBeAround(0.0, 0.2)
485
485
  expect($ghost2.css('opacity')).toBeAround(1.0, 0.2)
486
486
  done()
@@ -534,7 +534,7 @@ describe 'up.flow', ->
534
534
  promise = up.extract('.element', '<div class="element">version 2</div>', transition: 'cross-fade', duration: 30)
535
535
  promise.then(resolution)
536
536
  expect(resolution).not.toHaveBeenCalled()
537
- @setTimer 50, ->
537
+ u.setTimer 50, ->
538
538
  expect(resolution).toHaveBeenCalled()
539
539
  done()
540
540
 
@@ -1,4 +1,6 @@
1
1
  describe 'up.history', ->
2
+
3
+ u = up.util
2
4
 
3
5
  describe 'Javascript functions', ->
4
6
 
@@ -74,23 +76,23 @@ describe 'up.history', ->
74
76
  $('.viewport').scrollTop(250)
75
77
 
76
78
  history.back()
77
- @setTimer 50, =>
79
+ u.setTimer 50, ->
78
80
  respond() # we need to respond since we've never requested /two with the popTarget
79
81
  expect($('.viewport').scrollTop()).toBe(150)
80
82
 
81
83
  history.back()
82
- @setTimer 50, =>
84
+ u.setTimer 50, ->
83
85
  respond() # we need to respond since we've never requested /one with the popTarget
84
86
  expect($('.viewport').scrollTop()).toBe(50)
85
87
 
86
88
  history.forward()
87
- @setTimer 50, =>
89
+ u.setTimer 50, ->
88
90
  # No need to respond since we requested /two with the popTarget
89
91
  # when we went backwards
90
92
  expect($('.viewport').scrollTop()).toBe(150)
91
93
 
92
94
  history.forward()
93
- @setTimer 50, =>
95
+ u.setTimer 50, ->
94
96
  respond() # we need to respond since we've never requested /three with the popTarget
95
97
  expect($('.viewport').scrollTop()).toBe(250)
96
98
  done()
@@ -83,21 +83,21 @@ describe 'up.link', ->
83
83
  expect(document.title).toEqual('title from three')
84
84
 
85
85
  history.back()
86
- @setTimer 50, =>
86
+ u.setTimer 50, ->
87
87
  respondWith('restored text from two', 'restored title from two')
88
88
  expect($('.target')).toHaveText('restored text from two')
89
89
  expect(location.pathname).toEqual('/two')
90
90
  expect(document.title).toEqual('restored title from two')
91
91
 
92
92
  history.back()
93
- @setTimer 50, =>
93
+ u.setTimer 50, ->
94
94
  respondWith('restored text from one', 'restored title from one')
95
95
  expect($('.target')).toHaveText('restored text from one')
96
96
  expect(location.pathname).toEqual('/one')
97
97
  expect(document.title).toEqual('restored title from one')
98
98
 
99
99
  history.forward()
100
- @setTimer 50, =>
100
+ u.setTimer 50, ->
101
101
  # Since the response is cached, we don't have to respond
102
102
  expect($('.target')).toHaveText('restored text from two', 'restored title from two')
103
103
  expect(location.pathname).toEqual('/two')
@@ -105,6 +105,115 @@ describe 'up.link', ->
105
105
 
106
106
  done()
107
107
 
108
+ it 'does not add additional history entries when linking to the current URL', (done) ->
109
+
110
+ # By default, up.history will replace the <body> tag when
111
+ # the user presses the back-button. We reconfigure this
112
+ # so we don't lose the Jasmine runner interface.
113
+ up.history.config.popTargets = ['.container']
114
+
115
+ up.proxy.config.cacheExpiry = 0
116
+
117
+ respondWith = (text) =>
118
+ @respondWith """
119
+ <div class="container">
120
+ <div class='target'>#{text}</div>
121
+ </div>
122
+ """
123
+
124
+ followAndRespond = ($link, text) =>
125
+ promise = up.follow($link)
126
+ respondWith(text)
127
+ promise
128
+
129
+ $link1 = affix('a[href="/one"][up-target=".target"]')
130
+ $link2 = affix('a[href="/two"][up-target=".target"]')
131
+ $container = affix('.container')
132
+ $target = affix('.target').appendTo($container).text('original text')
133
+
134
+ followAndRespond($link1, 'text from one').then =>
135
+ expect($('.target')).toHaveText('text from one')
136
+ expect(location.pathname).toEqual('/one')
137
+
138
+ followAndRespond($link2, 'text from two').then =>
139
+ expect($('.target')).toHaveText('text from two')
140
+ expect(location.pathname).toEqual('/two')
141
+
142
+ followAndRespond($link2, 'text from two').then =>
143
+ expect($('.target')).toHaveText('text from two')
144
+ expect(location.pathname).toEqual('/two')
145
+
146
+ history.back()
147
+ u.setTimer 50, ->
148
+ respondWith('restored text from one')
149
+ expect($('.target')).toHaveText('restored text from one')
150
+ expect(location.pathname).toEqual('/one')
151
+
152
+ history.forward()
153
+ u.setTimer 50, ->
154
+ respondWith('restored text from two')
155
+ expect($('.target')).toHaveText('restored text from two')
156
+ expect(location.pathname).toEqual('/two')
157
+
158
+ done()
159
+
160
+ it 'does adds additional history entries when linking to the current URL, but with a different hash', (done) ->
161
+
162
+ # By default, up.history will replace the <body> tag when
163
+ # the user presses the back-button. We reconfigure this
164
+ # so we don't lose the Jasmine runner interface.
165
+ up.history.config.popTargets = ['.container']
166
+
167
+ up.proxy.config.cacheExpiry = 0
168
+
169
+ respondWith = (text) =>
170
+ @respondWith """
171
+ <div class="container">
172
+ <div class='target'>#{text}</div>
173
+ </div>
174
+ """
175
+
176
+ followAndRespond = ($link, text) =>
177
+ promise = up.follow($link)
178
+ respondWith(text)
179
+ promise
180
+
181
+ $link1 = affix('a[href="/one"][up-target=".target"]')
182
+ $link2 = affix('a[href="/two"][up-target=".target"]')
183
+ $link2WithHash = affix('a[href="/two#hash"][up-target=".target"]')
184
+ $container = affix('.container')
185
+ $target = affix('.target').appendTo($container).text('original text')
186
+
187
+ followAndRespond($link1, 'text from one').then =>
188
+ expect($('.target')).toHaveText('text from one')
189
+ expect(location.pathname).toEqual('/one')
190
+ expect(location.hash).toEqual('')
191
+
192
+ followAndRespond($link2, 'text from two').then =>
193
+ expect($('.target')).toHaveText('text from two')
194
+ expect(location.pathname).toEqual('/two')
195
+ expect(location.hash).toEqual('')
196
+
197
+ followAndRespond($link2WithHash, 'text from two with hash').then =>
198
+ expect($('.target')).toHaveText('text from two with hash')
199
+ expect(location.pathname).toEqual('/two')
200
+ expect(location.hash).toEqual('#hash')
201
+
202
+ history.back()
203
+ u.setTimer 50, ->
204
+ respondWith('restored text from two')
205
+ expect($('.target')).toHaveText('restored text from two')
206
+ expect(location.pathname).toEqual('/two')
207
+ expect(location.hash).toEqual('')
208
+
209
+ history.forward()
210
+ u.setTimer 50, ->
211
+ respondWith('restored text from two with hash')
212
+ expect($('.target')).toHaveText('restored text from two with hash')
213
+ expect(location.pathname).toEqual('/two')
214
+ expect(location.hash).toEqual('#hash')
215
+ done()
216
+
108
217
  describe 'with { restoreScroll: true } option', ->
109
218
 
110
219
  it 'does not reveal, but instead restores the scroll positions of all viewports around the target', ->
@@ -230,7 +339,7 @@ describe 'up.link', ->
230
339
  it 'does not follow a form with up-target attribute (bugfix)', ->
231
340
  $form = affix('form[up-target]')
232
341
  up.hello($form)
233
- followSpy = up.link.knife.mock('follow')
342
+ followSpy = up.link.knife.mock('follow').and.returnValue(u.resolvedPromise())
234
343
  $form.click()
235
344
  expect(followSpy).not.toHaveBeenCalled()
236
345
 
@@ -269,7 +378,7 @@ describe 'up.link', ->
269
378
 
270
379
  beforeEach ->
271
380
  @$link = affix('a[href="/path"][up-follow]')
272
- @followSpy = up.link.knife.mock('follow')
381
+ @followSpy = up.link.knife.mock('follow').and.returnValue(u.resolvedPromise())
273
382
  @defaultSpy = up.link.knife.mock('allowDefault').and.callFake((event) -> event.preventDefault())
274
383
 
275
384
  it "calls up.follow with the clicked link", ->
@@ -26,6 +26,25 @@ describe 'up.modal', ->
26
26
  expect($('.up-modal-dialog .after')).not.toExist()
27
27
  done()
28
28
 
29
+ describe 'up.modal.extract', ->
30
+
31
+ it 'opens a modal by extracting the given selector from the given HTML string', ->
32
+ oldHref = location.href
33
+ up.modal.extract '.middle', """
34
+ <div class="before">new-before</div>
35
+ <div class="middle">new-middle</div>
36
+ <div class="after">new-after</div>
37
+ """
38
+ expect($('.up-modal')).toExist()
39
+ expect($('.up-modal-dialog')).toExist()
40
+ expect($('.up-modal-dialog .middle')).toExist()
41
+ expect($('.up-modal-dialog .middle')).toHaveText('new-middle')
42
+ expect($('.up-modal-dialog .before')).not.toExist()
43
+ expect($('.up-modal-dialog .after')).not.toExist()
44
+
45
+ # Can't change URLs
46
+ expect(location.href).toEqual(oldHref)
47
+
29
48
  describe 'up.modal.visit', ->
30
49
 
31
50
  it "brings its own scrollbar, padding the body on the right in order to prevent jumping", (done) ->
@@ -34,11 +53,11 @@ describe 'up.modal', ->
34
53
  @respondWith('<div class="container">text</div>')
35
54
 
36
55
  promise.then ->
37
-
38
56
  $modal = $('.up-modal')
57
+ $viewport = $modal.find('.up-modal-viewport')
39
58
  $body = $('body')
40
59
  expect($modal).toExist()
41
- expect($modal.css('overflow-y')).toEqual('scroll')
60
+ expect($viewport.css('overflow-y')).toEqual('scroll')
42
61
  expect($body.css('overflow-y')).toEqual('hidden')
43
62
  expect(parseInt($body.css('padding-right'))).toBeAround(assumedScrollbarWidth, 10)
44
63
 
@@ -80,12 +99,13 @@ describe 'up.modal', ->
80
99
  it 'returns the URL behind the modal overlay', (done) ->
81
100
  up.history.replace('/foo')
82
101
  expect(up.modal.coveredUrl()).toBeUndefined()
83
- up.modal.visit('/bar', target: '.container')
102
+ visitPromise = up.modal.visit('/bar', target: '.container')
84
103
  @respondWith('<div class="container">text</div>')
85
- expect(up.modal.coveredUrl()).toEndWith('/foo')
86
- up.modal.close().then ->
87
- expect(up.modal.coveredUrl()).toBeUndefined()
88
- done()
104
+ visitPromise.then ->
105
+ expect(up.modal.coveredUrl()).toEndWith('/foo')
106
+ up.modal.close().then ->
107
+ expect(up.modal.coveredUrl()).toBeUndefined()
108
+ done()
89
109
 
90
110
 
91
111
  describe 'up.modal.close', ->
@@ -104,7 +124,7 @@ describe 'up.modal', ->
104
124
 
105
125
  beforeEach ->
106
126
  @$link = affix('a[href="/path"][up-modal=".target"]')
107
- @followSpy = up.modal.knife.mock('follow')
127
+ @followSpy = up.modal.knife.mock('follow').and.returnValue(u.resolvedPromise())
108
128
  @defaultSpy = up.link.knife.mock('allowDefault').and.callFake((event) -> event.preventDefault())
109
129
 
110
130
  it 'opens the clicked link in a modal', ->
@@ -253,13 +273,3 @@ describe 'up.modal', ->
253
273
  @respondWith("<div class='popup-content'></div>")
254
274
  expect($('.up-modal')).toExist()
255
275
  expect($('.up-popup')).toExist()
256
-
257
- describe 'when following links inside a modal', ->
258
-
259
- it 'prefers to replace a selector within the modal', ->
260
-
261
- it 'auto-closes the modal if a selector behind the modal gets replaced'
262
-
263
- it "doesn't auto-close the modal if a selector behind the modal if the modal is sticky"
264
-
265
- it "doesn't auto-close the modal if the new fragment is a popup"