unpoly-rails 0.37.0 → 0.50.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.

Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -25
  3. data/LICENSE +1 -1
  4. data/README_RAILS.md +4 -2
  5. data/Rakefile +6 -1
  6. data/dist/unpoly.js +3192 -2198
  7. data/dist/unpoly.min.js +4 -3
  8. data/lib/assets/javascripts/unpoly/browser.coffee +51 -63
  9. data/lib/assets/javascripts/unpoly/bus.coffee +58 -33
  10. data/lib/assets/javascripts/unpoly/classes/cache.coffee +117 -0
  11. data/lib/assets/javascripts/unpoly/{dom → classes}/extract_cascade.coffee +3 -3
  12. data/lib/assets/javascripts/unpoly/{dom → classes}/extract_plan.coffee +1 -1
  13. data/lib/assets/javascripts/unpoly/classes/field_observer.coffee +57 -0
  14. data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +52 -0
  15. data/lib/assets/javascripts/unpoly/classes/motion_tracker.coffee +95 -0
  16. data/lib/assets/javascripts/unpoly/classes/record.coffee +16 -0
  17. data/lib/assets/javascripts/unpoly/classes/request.coffee +228 -0
  18. data/lib/assets/javascripts/unpoly/classes/response.coffee +138 -0
  19. data/lib/assets/javascripts/unpoly/dom.coffee +151 -142
  20. data/lib/assets/javascripts/unpoly/feedback.coffee +67 -38
  21. data/lib/assets/javascripts/unpoly/form.coffee +156 -139
  22. data/lib/assets/javascripts/unpoly/history.coffee +22 -19
  23. data/lib/assets/javascripts/unpoly/layout.coffee +108 -90
  24. data/lib/assets/javascripts/unpoly/link.coffee +159 -158
  25. data/lib/assets/javascripts/unpoly/log.coffee +5 -5
  26. data/lib/assets/javascripts/unpoly/modal.coffee +93 -81
  27. data/lib/assets/javascripts/unpoly/motion.coffee +291 -250
  28. data/lib/assets/javascripts/unpoly/popup.coffee +67 -53
  29. data/lib/assets/javascripts/unpoly/protocol.coffee +67 -16
  30. data/lib/assets/javascripts/unpoly/proxy.coffee +282 -211
  31. data/lib/assets/javascripts/unpoly/rails.coffee +3 -14
  32. data/lib/assets/javascripts/unpoly/syntax.coffee +54 -49
  33. data/lib/assets/javascripts/unpoly/tooltip.coffee +18 -25
  34. data/lib/assets/javascripts/unpoly/util.coffee +236 -477
  35. data/lib/assets/javascripts/unpoly.coffee +1 -1
  36. data/lib/unpoly/rails/inspector.rb +67 -22
  37. data/lib/unpoly/rails/version.rb +1 -1
  38. data/package.json +1 -1
  39. data/spec_app/Gemfile.lock +13 -13
  40. data/spec_app/app/assets/javascripts/integration_test.coffee +1 -0
  41. data/spec_app/app/assets/javascripts/jasmine_specs.coffee +1 -1
  42. data/spec_app/app/assets/stylesheets/jasmine_specs.sass +10 -0
  43. data/spec_app/app/controllers/binding_test_controller.rb +19 -2
  44. data/spec_app/app/controllers/method_test_controller.rb +16 -0
  45. data/spec_app/app/views/layouts/jasmine_rails/spec_runner.html.erb +20 -0
  46. data/spec_app/app/views/method_test/form_target.erb +17 -0
  47. data/spec_app/app/views/method_test/page1.erb +11 -0
  48. data/spec_app/app/views/method_test/page2.erb +6 -0
  49. data/spec_app/app/views/pages/start.erb +33 -19
  50. data/spec_app/config/initializers/assets.rb +5 -0
  51. data/spec_app/config/routes.rb +3 -0
  52. data/spec_app/spec/controllers/binding_test_controller_spec.rb +82 -27
  53. data/spec_app/spec/javascripts/helpers/agent_detector.coffee +17 -0
  54. data/spec_app/spec/javascripts/helpers/async_sequence.js.coffee +102 -0
  55. data/spec_app/spec/javascripts/helpers/last_request.js.coffee +1 -1
  56. data/spec_app/spec/javascripts/helpers/mock_ajax.js.coffee +5 -2
  57. data/spec_app/spec/javascripts/helpers/promise_state.js +18 -0
  58. data/spec_app/spec/javascripts/helpers/protect_jasmine_runner.coffee +9 -0
  59. data/spec_app/spec/javascripts/helpers/reset_history.js.coffee +22 -0
  60. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +11 -3
  61. data/spec_app/spec/javascripts/helpers/show_lib_versions.coffee +10 -0
  62. data/spec_app/spec/javascripts/helpers/to_be_error.coffee +5 -0
  63. data/spec_app/spec/javascripts/helpers/to_match_url.coffee +13 -0
  64. data/spec_app/spec/javascripts/helpers/trigger.js.coffee +13 -6
  65. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +92 -33
  66. data/spec_app/spec/javascripts/up/bus_spec.js.coffee +64 -15
  67. data/spec_app/spec/javascripts/up/classes/.keep +0 -0
  68. data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +1 -0
  69. data/spec_app/spec/javascripts/up/dom_spec.js.coffee +759 -551
  70. data/spec_app/spec/javascripts/up/feedback_spec.js.coffee +155 -82
  71. data/spec_app/spec/javascripts/up/form_spec.js.coffee +490 -349
  72. data/spec_app/spec/javascripts/up/history_spec.js.coffee +226 -179
  73. data/spec_app/spec/javascripts/up/layout_spec.js.coffee +253 -185
  74. data/spec_app/spec/javascripts/up/link_spec.js.coffee +416 -270
  75. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +459 -330
  76. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +198 -153
  77. data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +9 -0
  78. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +240 -175
  79. data/spec_app/spec/javascripts/up/protocol_spec.js.coffee +38 -0
  80. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +777 -303
  81. data/spec_app/spec/javascripts/up/rails_spec.js.coffee +24 -8
  82. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +40 -23
  83. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +80 -66
  84. data/spec_app/spec/javascripts/up/util_spec.js.coffee +227 -201
  85. data/spec_app/vendor/asset-libs/es6-promise-4.1.6/es6-promise.auto.js +1159 -0
  86. metadata +30 -7
  87. data/spec_app/spec/javascripts/helpers/reset_path.js.coffee +0 -7
  88. data/spec_app/spec/javascripts/helpers/to_equal_url.coffee +0 -11
@@ -1,14 +1,11 @@
1
1
  ###*
2
- Browser history
3
- ===============
2
+ History
3
+ ========
4
4
 
5
5
  In an Unpoly app, every page has an URL.
6
6
 
7
7
  [Fragment updates](/up.link) automatically update the URL.
8
8
 
9
-
10
- Going back behavior .... configure.
11
-
12
9
  @class up.history
13
10
  ###
14
11
  up.history = (($) ->
@@ -22,12 +19,13 @@ up.history = (($) ->
22
19
  @param {Array} [config.popTargets=['body']]
23
20
  An array of CSS selectors to replace when the user goes
24
21
  back in history.
25
- @param {Boolean} [config.restoreScroll=true]
22
+ @param {boolean} [config.restoreScroll=true]
26
23
  Whether to restore the known scroll positions
27
24
  when the user goes back or forward in history.
28
25
  @stable
29
26
  ###
30
27
  config = u.config
28
+ enabled: true
31
29
  popTargets: ['body']
32
30
  restoreScroll: true
33
31
 
@@ -92,8 +90,8 @@ up.history = (($) ->
92
90
  browser's location bar for you.
93
91
 
94
92
  @function up.history.replace
95
- @param {String} url
96
- @experimental
93
+ @param {string} url
94
+ @internal
97
95
  ###
98
96
  replace = (url) ->
99
97
  manipulate('replaceState', url)
@@ -113,7 +111,7 @@ up.history = (($) ->
113
111
  Emits events [`up:history:push`](/up:history:push) and [`up:history:pushed`](/up:history:pushed).
114
112
 
115
113
  @function up.history.push
116
- @param {String} url
114
+ @param {string} url
117
115
  The URL for the history entry to be added.
118
116
  @experimental
119
117
  ###
@@ -121,14 +119,16 @@ up.history = (($) ->
121
119
  options = u.options(options, force: false)
122
120
  url = normalizeUrl(url)
123
121
  if (options.force || !isCurrentUrl(url)) && up.bus.nobodyPrevents('up:history:push', url: url, message: "Adding history entry for #{url}")
124
- manipulate('pushState', url)
125
- up.emit('up:history:pushed', url: url, message: "Advanced to location #{url}")
122
+ if manipulate('pushState', url)
123
+ up.emit('up:history:pushed', url: url, message: "Advanced to location #{url}")
124
+ else
125
+ up.emit('up:history:muted', url: url, message: "Did not advance to #{url} (history is unavailable)")
126
126
 
127
127
  ###*
128
128
  This event is [emitted](/up.emit) before a new history entry is added.
129
129
 
130
130
  @event up:history:push
131
- @param {String} event.url
131
+ @param {string} event.url
132
132
  The URL for the history entry that is going to be added.
133
133
  @param event.preventDefault()
134
134
  Event listeners may call this method to prevent the history entry from being added.
@@ -139,18 +139,19 @@ up.history = (($) ->
139
139
  This event is [emitted](/up.emit) after a new history entry has been added.
140
140
 
141
141
  @event up:history:pushed
142
- @param {String} event.url
142
+ @param {string} event.url
143
143
  The URL for the history entry that has been added.
144
144
  @experimental
145
145
  ###
146
146
 
147
147
  manipulate = (method, url) ->
148
- if up.browser.canPushState()
148
+ if up.browser.canPushState() && config.enabled
149
149
  state = buildState()
150
150
  window.history[method](state, '', url)
151
151
  observeNewUrl(currentUrl())
152
+ true
152
153
  else
153
- up.fail "This browser doesn't support history.#{method}"
154
+ false
154
155
 
155
156
  buildState = ->
156
157
  fromUp: true
@@ -189,7 +190,7 @@ up.history = (($) ->
189
190
  History entries are restored when the user uses the *Back* or *Forward* button.
190
191
 
191
192
  @event up:history:restore
192
- @param {String} event.url
193
+ @param {string} event.url
193
194
  The URL for the history entry that has been restored.
194
195
  @internal
195
196
  ###
@@ -200,7 +201,7 @@ up.history = (($) ->
200
201
  History entries are restored when the user uses the *Back* or *Forward* button.
201
202
 
202
203
  @event up:history:restored
203
- @param {String} event.url
204
+ @param {string} event.url
204
205
  The URL for the history entry that has been restored.
205
206
  @experimental
206
207
  ###
@@ -225,6 +226,8 @@ up.history = (($) ->
225
226
  Note that this will *not* call `location.back()`, but will set
226
227
  the link's `up-href` attribute to the actual, previous URL.
227
228
 
229
+ If no previous URL is known, the link will not be changed.
230
+
228
231
  \#\#\# Example
229
232
 
230
233
  This link ...
@@ -239,10 +242,10 @@ up.history = (($) ->
239
242
  Go back
240
243
  </a>
241
244
 
242
- @selector [up-back]
245
+ @selector a[up-back]
243
246
  @stable
244
247
  ###
245
- up.compiler '[up-back]', ($link) ->
248
+ up.macro 'a[up-back], [up-href][up-back]', ($link) ->
246
249
  if u.isPresent(previousUrl)
247
250
  u.setMissingAttrs $link,
248
251
  'up-href': previousUrl,
@@ -4,7 +4,7 @@ Application layout
4
4
 
5
5
  You can [make Unpoly aware](/up.layout.config) of fixed elements in your
6
6
  layout, such as navigation bars or headers. Unpoly will respect these sticky
7
- elements when [revealing elements](/up.reveal) or [opening a modal dialog](/up-modal).
7
+ elements when [revealing elements](/up.reveal) or [opening a modal dialog](/a-up-modal).
8
8
 
9
9
  This modules also contains functions to programmatically [scroll a viewport](/up.scroll)
10
10
  or [reveal an element within its viewport](/up.reveal).
@@ -41,17 +41,17 @@ up.layout = (($) ->
41
41
  An array of CSS selectors that find elements anchored to the
42
42
  right edge of the screen (using `right:0` with `position: fixed` or `position: absolute`).
43
43
  See [`[up-anchored="right"]`](/up-anchored-right) for details.
44
- @param {Number} [config.duration=0]
44
+ @param {number} [config.duration=0]
45
45
  The duration of the scrolling animation in milliseconds.
46
46
  Setting this to `0` will disable scrolling animations.
47
- @param {String} [config.easing='swing']
47
+ @param {string} [config.easing='swing']
48
48
  The timing function that controls the animation's acceleration.
49
49
  See [W3C documentation](http://www.w3.org/TR/css3-transitions/#transition-timing-function)
50
50
  for a list of pre-defined timing functions.
51
- @param {Number} [config.snap=50]
51
+ @param {number} [config.snap=50]
52
52
  When [revealing](/up.reveal) elements, Unpoly will scroll an viewport
53
53
  to the top when the revealed element is closer to the top than `config.snap`.
54
- @param {Number} [config.substance=150]
54
+ @param {number} [config.substance=150]
55
55
  A number indicating how many top pixel rows of an element to [reveal](/up.reveal).
56
56
  @stable
57
57
  ###
@@ -65,15 +65,16 @@ up.layout = (($) ->
65
65
  substance: 150
66
66
  easing: 'swing'
67
67
 
68
- lastScrollTops = u.cache
68
+ lastScrollTops = new up.Cache
69
69
  size: 30,
70
70
  key: up.history.normalizeUrl
71
71
 
72
+ scrollingTracker = new up.MotionTracker('scrolling')
73
+
72
74
  reset = ->
73
75
  config.reset()
74
76
  lastScrollTops.clear()
75
-
76
- SCROLL_PROMISE_KEY = 'up-scroll-promise'
77
+ scrollingTracker.finish()
77
78
 
78
79
  ###*
79
80
  Scrolls the given viewport to the given Y-position.
@@ -101,63 +102,67 @@ up.layout = (($) ->
101
102
  last frame before the next animation is started.
102
103
 
103
104
  @function up.scroll
104
- @param {String|Element|jQuery} viewport
105
+ @param {string|Element|jQuery} viewport
105
106
  The container element to scroll.
106
- @param {Number} scrollPos
107
+ @param {number} scrollPos
107
108
  The absolute number of pixels to set the scroll position to.
108
- @param {Number}[options.duration]
109
+ @param {number}[options.duration]
109
110
  The number of miliseconds for the scrolling's animation.
110
- @param {String}[options.easing]
111
+ @param {string}[options.easing]
111
112
  The timing function that controls the acceleration for the scrolling's animation.
112
- @return {Deferred}
113
- A promise that will be resolved when the scrolling ends.
113
+ @return {Promise}
114
+ A promise that will be fulfilled when the scrolling ends.
114
115
  @experimental
115
116
  ###
116
117
  scroll = (viewport, scrollTop, options) ->
117
- $viewport = $(viewport)
118
+ $scrollable = scrollableElementForViewport(viewport)
118
119
  options = u.options(options)
119
- duration = u.option(options.duration, config.duration)
120
- easing = u.option(options.easing, config.easing)
120
+ options.duration = u.option(options.duration, config.duration)
121
+ options.easing = u.option(options.easing, config.easing)
121
122
 
122
- finishScrolling($viewport)
123
-
124
- if duration > 0
125
- deferred = $.Deferred()
123
+ finishScrolling($scrollable).then ->
124
+ if up.motion.isEnabled() && options.duration > 0
125
+ scrollWithAnimateNow($scrollable, scrollTop, options)
126
+ else
127
+ scrollAbruptlyNow($scrollable, scrollTop)
126
128
 
127
- $viewport.data(SCROLL_PROMISE_KEY, deferred)
128
- deferred.then ->
129
- $viewport.removeData(SCROLL_PROMISE_KEY)
130
- # Since we're scrolling using #animate, #finish can be
131
- # used to jump to the last frame:
132
- # https://api.jquery.com/finish/
133
- $viewport.finish()
129
+ scrollableElementForViewport = (viewport) ->
130
+ $viewport = $(viewport)
131
+ if $viewport.get(0) == document
132
+ $('html, body') # FML
133
+ else
134
+ $viewport
134
135
 
135
- targetProps =
136
- scrollTop: scrollTop
136
+ scrollWithAnimateNow = ($scrollable, scrollTop, animateOptions) ->
137
+ start = ->
138
+ finish = ->
139
+ # jQuery exposes a finish() method that completes all animations orchestrated through jQuery.
140
+ # This will also resolve the promise returned by $element.animate(..).promise().
141
+ $scrollable.finish()
137
142
 
138
- if $viewport.get(0) == document
139
- $viewport = $('html, body') # FML
143
+ $scrollable.on(scrollingTracker.eventName, finish)
144
+ scrollDone = $scrollable.animate({ scrollTop }, animateOptions).promise()
145
+ scrollDone.then -> $scrollable.off(scrollingTracker.eventName)
146
+ scrollDone
140
147
 
141
- $viewport.animate targetProps,
142
- duration: duration,
143
- easing: easing,
144
- complete: -> deferred.resolve()
148
+ # Tracker will either finish or wait for previous scrolling animations before starting the next
149
+ scrollingTracker.claim($scrollable, start)
145
150
 
146
- deferred
147
- else
148
- $viewport.scrollTop(scrollTop)
149
- u.resolvedDeferred()
151
+ scrollAbruptlyNow = ($scrollable, scrollTop) ->
152
+ $scrollable.scrollTop(scrollTop)
153
+ Promise.resolve()
150
154
 
151
155
  ###*
156
+ Finishes scrolling animations in the given element, its ancestors or its descendants.
157
+
152
158
  @function up.layout.finishScrolling
153
- @param {String|Element|jQuery}
154
- The element that might currently be scrolling.
159
+ @param {string|Element|jQuery}
160
+ @return {Promise}
155
161
  @internal
156
162
  ###
157
- finishScrolling = (elementOrSelector) ->
158
- $(elementOrSelector).each ->
159
- if existingScrolling = $(this).data(SCROLL_PROMISE_KEY)
160
- existingScrolling.resolve()
163
+ finishScrolling = (element) ->
164
+ $scrollable = scrollableElementForViewport(element)
165
+ scrollingTracker.finish($scrollable)
161
166
 
162
167
  ###*
163
168
  @function up.layout.anchoredRight
@@ -166,8 +171,12 @@ up.layout = (($) ->
166
171
  anchoredRight = ->
167
172
  u.multiSelector(config.anchoredRight).select()
168
173
 
174
+ ###*
175
+ @function measureObstruction
176
+ @return {Object}
177
+ @internal
178
+ ###
169
179
  measureObstruction = ->
170
-
171
180
  measurePosition = (obstructor, cssAttr) ->
172
181
  $obstructor = $(obstructor)
173
182
  anchorPosition = $obstructor.css(cssAttr)
@@ -215,16 +224,16 @@ up.layout = (($) ->
215
224
  - [configure default options](/up.layout.config) for `fixedTop` or `fixedBottom`
216
225
 
217
226
  @function up.reveal
218
- @param {String|Element|jQuery} element
219
- @param {Number} [options.duration]
220
- @param {String} [options.easing]
221
- @param {String} [options.snap]
222
- @param {String|Element|jQuery} [options.viewport]
223
- @param {Boolean} [options.top=false]
227
+ @param {string|Element|jQuery} element
228
+ @param {number} [options.duration]
229
+ @param {string} [options.easing]
230
+ @param {string} [options.snap]
231
+ @param {string|Element|jQuery} [options.viewport]
232
+ @param {boolean} [options.top=false]
224
233
  Whether to scroll the viewport so that the first element row aligns
225
234
  with the top edge of the viewport.
226
- @return {Deferred}
227
- A promise that will be resolved when the element is revealed.
235
+ @return {Promise}
236
+ A promise that fulfills when the element is revealed.
228
237
  @stable
229
238
  ###
230
239
  reveal = (elementOrSelector, options) ->
@@ -279,7 +288,7 @@ up.layout = (($) ->
279
288
  if newScrollPos != originalScrollPos
280
289
  scroll($viewport, newScrollPos, options)
281
290
  else
282
- u.resolvedDeferred()
291
+ Promise.resolve()
283
292
 
284
293
  ###*
285
294
  [Reveals](/up.reveal) an element matching the `#hash` in the current URL.
@@ -291,16 +300,15 @@ up.layout = (($) ->
291
300
  This is called automatically when the page loads initially.
292
301
 
293
302
  @function up.layout.revealHash
303
+ @return {Promise}
304
+ A promise that is fulfilled when scroll position has changed to match the location hash.
294
305
  @experimental
295
306
  ###
296
307
  revealHash = ->
297
- if hash = up.browser.hash()
298
- if $match = firstHashTarget(hash)
299
- reveal($match)
300
- else
301
- u.rejectedPromise()
308
+ if (hash = up.browser.hash()) && ($match = firstHashTarget(hash))
309
+ reveal($match)
302
310
  else
303
- u.resolvedPromise()
311
+ Promise.resolve()
304
312
 
305
313
  viewportSelector = ->
306
314
  u.multiSelector(config.viewports)
@@ -311,7 +319,7 @@ up.layout = (($) ->
311
319
  Throws an error if no viewport could be found.
312
320
 
313
321
  @function up.layout.viewportOf
314
- @param {String|Element|jQuery} selectorOrElement
322
+ @param {string|Element|jQuery} selectorOrElement
315
323
  @internal
316
324
  ###
317
325
  viewportOf = (selectorOrElement, options = {}) ->
@@ -326,13 +334,13 @@ up.layout = (($) ->
326
334
  given selector or element.
327
335
 
328
336
  @function up.layout.viewportsWithin
329
- @param {String|Element|jQuery} selectorOrElement
337
+ @param {string|Element|jQuery} selectorOrElement
330
338
  @return jQuery
331
339
  @internal
332
340
  ###
333
341
  viewportsWithin = (selectorOrElement) ->
334
342
  $element = $(selectorOrElement)
335
- viewportSelector().findWithSelf($element)
343
+ viewportSelector().selectInSubtree($element)
336
344
 
337
345
  ###*
338
346
  Returns a jQuery collection of all the viewports on the screen.
@@ -360,7 +368,7 @@ up.layout = (($) ->
360
368
  => { '.main': 0, '.sidebar': 73 }
361
369
 
362
370
  @function up.layout.scrollTops
363
- @return Object<String, Number>
371
+ @return Object<string, number>
364
372
  @internal
365
373
  ###
366
374
  scrollTops = ->
@@ -396,14 +404,13 @@ up.layout = (($) ->
396
404
  Unpoly automatically saves scroll positions whenever a fragment was updated on the page.
397
405
 
398
406
  @function up.layout.saveScroll
399
- @param {String} [options.url]
400
- @param {Object<String, Number>} [options.tops]
407
+ @param {string} [options.url]
408
+ @param {Object<string, number>} [options.tops]
401
409
  @experimental
402
410
  ###
403
411
  saveScroll = (options = {}) ->
404
412
  url = u.option(options.url, up.history.url())
405
413
  tops = u.option(options.tops, scrollTops())
406
- up.puts('Saving scroll positions for URL %s (%o)', url, tops)
407
414
  lastScrollTops.set(url, tops)
408
415
 
409
416
  ###*
@@ -417,10 +424,11 @@ up.layout = (($) ->
417
424
  @param {jQuery} [options.around]
418
425
  If set, only restores viewports that are either an ancestor
419
426
  or descendant of the given element.
427
+ @return {Promise}
428
+ A promise that will be fulfilled once scroll positions have been restored.
420
429
  @experimental
421
430
  ###
422
431
  restoreScroll = (options = {}) ->
423
-
424
432
  url = up.history.url()
425
433
 
426
434
  $viewports = undefined
@@ -435,37 +443,48 @@ up.layout = (($) ->
435
443
  scrollTopsForUrl = lastScrollTops.get(url) || {}
436
444
 
437
445
  up.log.group 'Restoring scroll positions for URL %s to %o', url, scrollTopsForUrl, ->
438
- $viewports.each ->
439
- $viewport = $(this)
440
- key = scrollTopKey($viewport)
446
+ allScrollPromises = u.map $viewports, (viewport) ->
447
+ key = scrollTopKey(viewport)
441
448
  scrollTop = scrollTopsForUrl[key] || 0
442
- scroll($viewport, scrollTop, duration: 0)
449
+ scroll(viewport, scrollTop, duration: 0)
443
450
 
444
- # Since scrolling happens without animation, we don't need to
445
- # join promises from the up.scroll call above
446
- u.resolvedDeferred()
451
+ Promise.all(allScrollPromises)
447
452
 
448
453
  ###*
449
454
  @function up.layout.revealOrRestoreScroll
450
- @return {Deferred}
451
- A promise for when the revealing or scroll restoration ends
455
+ @param {boolean} [options.restoreScroll]
456
+ @param {boolean|string} [options.reveal]
457
+ @return {Promise}
458
+ A promise that is fulfilled when the element is revealed or
459
+ the scroll position is restored.
452
460
  @internal
453
461
  ###
454
462
  revealOrRestoreScroll = (selectorOrElement, options) ->
455
463
  $element = $(selectorOrElement)
464
+
456
465
  if options.restoreScroll
457
- restoreScroll(around: $element)
458
- else if options.reveal
466
+ return restoreScroll(around: $element)
467
+
468
+ if options.reveal
459
469
  revealOptions = {}
460
- if options.source
461
- parsed = u.parseUrl(options.source)
462
- if $target = firstHashTarget(parsed.hash)
463
- $element = $target
464
- revealOptions.top = true
465
- reveal($element, revealOptions)
466
- else
467
- u.resolvedDeferred()
470
+ if u.isString(options.reveal)
471
+ selector = revealSelector(options.reveal)
472
+ $element = up.first(selector) || $element
473
+ revealOptions.top = true
474
+ return reveal($element, revealOptions)
475
+
476
+ # If we didn't need to scroll above, just return a resolved promise
477
+ # to fulfill this function's signature.
478
+ return Promise.resolve()
468
479
 
480
+ ###*
481
+ @internal
482
+ ###
483
+ revealSelector = (selector, options) ->
484
+ selector = up.dom.resolveSelector(selector, options)
485
+ if selector[0] == '#'
486
+ selector += ", a[name='#{selector}']"
487
+ selector
469
488
 
470
489
  ###*
471
490
  Marks this element as a scrolling container ("viewport").
@@ -613,7 +632,6 @@ up.layout = (($) ->
613
632
  revealHash: revealHash
614
633
  firstHashTarget: firstHashTarget
615
634
  scroll: scroll
616
- finishScrolling: finishScrolling
617
635
  config: config
618
636
  viewportOf: viewportOf
619
637
  viewportsWithin: viewportsWithin