unpoly-rails 0.57.0 → 0.60.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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +393 -1
  3. data/Gemfile.lock +5 -2
  4. data/README.md +1 -1
  5. data/README_RAILS.md +1 -1
  6. data/Rakefile +10 -1
  7. data/design/es6.js +32 -0
  8. data/design/ie11.txt +9 -0
  9. data/design/measure_jquery/element_list.js +41 -0
  10. data/design/measure_jquery/up.on_vs_addEventListener.js +56 -0
  11. data/design/todo_jquery.txt +13 -0
  12. data/dist/unpoly-bootstrap3.js +8 -8
  13. data/dist/unpoly-bootstrap3.min.js +1 -1
  14. data/dist/unpoly.css +22 -20
  15. data/dist/unpoly.js +6990 -5336
  16. data/dist/unpoly.min.css +1 -1
  17. data/dist/unpoly.min.js +4 -4
  18. data/lib/assets/javascripts/unpoly-bootstrap3/viewport-ext.coffee +5 -0
  19. data/lib/assets/javascripts/unpoly.coffee +8 -6
  20. data/lib/assets/javascripts/unpoly/browser.coffee.erb +23 -118
  21. data/lib/assets/javascripts/unpoly/classes/body_shifter.coffee +36 -0
  22. data/lib/assets/javascripts/unpoly/classes/cache.coffee +4 -4
  23. data/lib/assets/javascripts/unpoly/classes/compile_pass.coffee +45 -39
  24. data/lib/assets/javascripts/unpoly/classes/config.coffee +9 -0
  25. data/lib/assets/javascripts/unpoly/classes/css_transition.coffee +18 -27
  26. data/lib/assets/javascripts/unpoly/classes/divertible_chain.coffee +39 -0
  27. data/lib/assets/javascripts/unpoly/classes/event_listener.coffee +116 -0
  28. data/lib/assets/javascripts/unpoly/classes/extract_cascade.coffee +8 -8
  29. data/lib/assets/javascripts/unpoly/classes/extract_plan.coffee +19 -19
  30. data/lib/assets/javascripts/unpoly/classes/field_observer.coffee +54 -31
  31. data/lib/assets/javascripts/unpoly/classes/{focus_tracker.coffee → focus_follower.coffee} +2 -2
  32. data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +25 -25
  33. data/lib/assets/javascripts/unpoly/classes/html_parser.coffee +4 -11
  34. data/lib/assets/javascripts/unpoly/classes/motion_controller.coffee +157 -0
  35. data/lib/assets/javascripts/unpoly/classes/params.coffee.erb +525 -0
  36. data/lib/assets/javascripts/unpoly/classes/record.coffee +8 -2
  37. data/lib/assets/javascripts/unpoly/classes/rect.js +21 -0
  38. data/lib/assets/javascripts/unpoly/classes/request.coffee +41 -35
  39. data/lib/assets/javascripts/unpoly/classes/response.coffee +7 -3
  40. data/lib/assets/javascripts/unpoly/classes/reveal_motion.coffee +102 -0
  41. data/lib/assets/javascripts/unpoly/classes/scroll_motion.coffee +67 -0
  42. data/lib/assets/javascripts/unpoly/classes/selector.coffee +60 -0
  43. data/lib/assets/javascripts/unpoly/classes/tether.coffee +105 -0
  44. data/lib/assets/javascripts/unpoly/classes/url_set.coffee +12 -7
  45. data/lib/assets/javascripts/unpoly/element.coffee.erb +1126 -0
  46. data/lib/assets/javascripts/unpoly/event.coffee.erb +437 -0
  47. data/lib/assets/javascripts/unpoly/feedback.coffee +73 -94
  48. data/lib/assets/javascripts/unpoly/form.coffee.erb +188 -181
  49. data/lib/assets/javascripts/unpoly/{dom.coffee.erb → fragment.coffee.erb} +250 -283
  50. data/lib/assets/javascripts/unpoly/framework.coffee +67 -0
  51. data/lib/assets/javascripts/unpoly/history.coffee +29 -28
  52. data/lib/assets/javascripts/unpoly/legacy.coffee +60 -0
  53. data/lib/assets/javascripts/unpoly/link.coffee.erb +127 -119
  54. data/lib/assets/javascripts/unpoly/log.coffee +99 -19
  55. data/lib/assets/javascripts/unpoly/modal.coffee.erb +95 -118
  56. data/lib/assets/javascripts/unpoly/motion.coffee.erb +158 -138
  57. data/lib/assets/javascripts/unpoly/namespace.coffee.erb +0 -5
  58. data/lib/assets/javascripts/unpoly/popup.coffee.erb +119 -102
  59. data/lib/assets/javascripts/unpoly/protocol.coffee +11 -15
  60. data/lib/assets/javascripts/unpoly/proxy.coffee +62 -65
  61. data/lib/assets/javascripts/unpoly/radio.coffee +3 -5
  62. data/lib/assets/javascripts/unpoly/rails.coffee +8 -9
  63. data/lib/assets/javascripts/unpoly/syntax.coffee.erb +173 -125
  64. data/lib/assets/javascripts/unpoly/toast.coffee +25 -24
  65. data/lib/assets/javascripts/unpoly/tooltip.coffee +89 -79
  66. data/lib/assets/javascripts/unpoly/util.coffee.erb +579 -1074
  67. data/lib/assets/javascripts/unpoly/{layout.coffee.erb → viewport.coffee.erb} +334 -264
  68. data/lib/assets/stylesheets/unpoly/dom.sass +1 -1
  69. data/lib/assets/stylesheets/unpoly/layout.sass +2 -0
  70. data/lib/assets/stylesheets/unpoly/popup.sass +0 -1
  71. data/lib/assets/stylesheets/unpoly/tooltip.sass +17 -12
  72. data/lib/unpoly/rails/version.rb +1 -1
  73. data/package.json +1 -2
  74. data/spec_app/Gemfile +2 -1
  75. data/spec_app/Gemfile.lock +38 -27
  76. data/spec_app/app/assets/javascripts/integration_test.coffee +1 -0
  77. data/spec_app/app/assets/javascripts/jasmine_specs.coffee +1 -2
  78. data/spec_app/app/assets/stylesheets/integration_test.sass +14 -1
  79. data/spec_app/app/controllers/scroll_test_controller.rb +5 -0
  80. data/spec_app/app/views/css_test/modal.erb +6 -6
  81. data/spec_app/app/views/css_test/popup.erb +44 -18
  82. data/spec_app/app/views/css_test/tooltip.erb +23 -4
  83. data/spec_app/app/views/error_test/trigger.erb +1 -1
  84. data/spec_app/app/views/form_test/basics/new.erb +1 -3
  85. data/spec_app/app/views/pages/start.erb +9 -2
  86. data/spec_app/app/views/reveal_test/long1.erb +1 -1
  87. data/spec_app/app/views/reveal_test/long2.erb +1 -1
  88. data/spec_app/app/views/reveal_test/within_document_viewport.erb +24 -0
  89. data/spec_app/app/views/reveal_test/within_overflowing_div_viewport.erb +28 -0
  90. data/spec_app/app/views/scroll_test/long1.erb +30 -0
  91. data/spec_app/config/routes.rb +1 -0
  92. data/spec_app/spec/javascripts/helpers/agent_detector.coffee +3 -0
  93. data/spec_app/spec/javascripts/helpers/async_sequence.js.coffee +1 -0
  94. data/spec_app/spec/javascripts/helpers/browser_switches.js.coffee +17 -5
  95. data/spec_app/spec/javascripts/helpers/enable_logging.js.coffee +1 -1
  96. data/spec_app/spec/javascripts/helpers/fixture.js.coffee +25 -0
  97. data/spec_app/spec/javascripts/helpers/jquery_no_conflict.js +1 -0
  98. data/spec_app/spec/javascripts/helpers/last_request.js.coffee +1 -0
  99. data/spec_app/spec/javascripts/helpers/mock_ajax.js.coffee +1 -1
  100. data/spec_app/spec/javascripts/helpers/parse_form_data.js.coffee +2 -2
  101. data/spec_app/spec/javascripts/helpers/protect_jasmine_runner.coffee +4 -1
  102. data/spec_app/spec/javascripts/helpers/remove_body_margin.js.coffee +3 -0
  103. data/spec_app/spec/javascripts/helpers/reset_history.js.coffee +2 -1
  104. data/spec_app/spec/javascripts/helpers/reset_knife.js.coffee +2 -2
  105. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +18 -11
  106. data/spec_app/spec/javascripts/helpers/restore_body_scroll.js.coffee +3 -0
  107. data/spec_app/spec/javascripts/helpers/show_lib_versions.coffee +3 -0
  108. data/spec_app/spec/javascripts/helpers/spec_util.coffee +47 -0
  109. data/spec_app/spec/javascripts/helpers/to_be_around.js.coffee +3 -0
  110. data/spec_app/spec/javascripts/helpers/to_be_array.coffee +5 -0
  111. data/spec_app/spec/javascripts/helpers/to_be_attached.coffee +6 -2
  112. data/spec_app/spec/javascripts/helpers/to_be_blank.js.coffee +3 -0
  113. data/spec_app/spec/javascripts/helpers/to_be_detached.coffee +6 -2
  114. data/spec_app/spec/javascripts/helpers/to_be_element.js.coffee +8 -0
  115. data/spec_app/spec/javascripts/helpers/to_be_error.coffee +3 -0
  116. data/spec_app/spec/javascripts/helpers/to_be_given.js.coffee +3 -0
  117. data/spec_app/spec/javascripts/helpers/to_be_hidden.js.coffee +8 -0
  118. data/spec_app/spec/javascripts/helpers/to_be_missing.js.coffee +3 -0
  119. data/spec_app/spec/javascripts/helpers/to_be_present.js.coffee +3 -0
  120. data/spec_app/spec/javascripts/helpers/to_be_scrolled_to.coffee +3 -0
  121. data/spec_app/spec/javascripts/helpers/to_be_visible.js.coffee +9 -0
  122. data/spec_app/spec/javascripts/helpers/to_contain.js.coffee +3 -0
  123. data/spec_app/spec/javascripts/helpers/to_end_with.js.coffee +3 -0
  124. data/spec_app/spec/javascripts/helpers/to_equal_jquery.js.coffee +1 -2
  125. data/spec_app/spec/javascripts/helpers/to_equal_node_list.coffee +7 -0
  126. data/spec_app/spec/javascripts/helpers/to_equal_via_is_equal.js.coffee +7 -0
  127. data/spec_app/spec/javascripts/helpers/to_have_class.js.coffee +10 -0
  128. data/spec_app/spec/javascripts/helpers/to_have_descendant.js.coffee +10 -0
  129. data/spec_app/spec/javascripts/helpers/to_have_length.js.coffee +8 -0
  130. data/spec_app/spec/javascripts/helpers/to_have_opacity.coffee +7 -3
  131. data/spec_app/spec/javascripts/helpers/to_have_own_property.js.coffee +3 -0
  132. data/spec_app/spec/javascripts/helpers/to_have_request_method.js.coffee +1 -0
  133. data/spec_app/spec/javascripts/helpers/to_have_text.js.coffee +9 -0
  134. data/spec_app/spec/javascripts/helpers/to_have_unhandled_rejections.coffee +0 -21
  135. data/spec_app/spec/javascripts/helpers/to_match_list.coffee +14 -0
  136. data/spec_app/spec/javascripts/helpers/to_match_selector.coffee +3 -0
  137. data/spec_app/spec/javascripts/helpers/to_match_text.js.coffee +4 -1
  138. data/spec_app/spec/javascripts/helpers/to_match_url.coffee +1 -0
  139. data/spec_app/spec/javascripts/helpers/trigger.js.coffee +91 -7
  140. data/spec_app/spec/javascripts/helpers/wait_until_dom_ready.js.coffee +3 -0
  141. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +23 -90
  142. data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +3 -0
  143. data/spec_app/spec/javascripts/up/classes/config_spec.coffee +24 -0
  144. data/spec_app/spec/javascripts/up/classes/divertible_chain_spec.coffee +45 -0
  145. data/spec_app/spec/javascripts/up/classes/focus_tracker_spec.coffee +5 -2
  146. data/spec_app/spec/javascripts/up/classes/params_spec.coffee +557 -0
  147. data/spec_app/spec/javascripts/up/classes/request_spec.coffee +7 -4
  148. data/spec_app/spec/javascripts/up/classes/scroll_motion_spec.js.coffee +51 -0
  149. data/spec_app/spec/javascripts/up/classes/store/memory_spec.js.coffee +3 -0
  150. data/spec_app/spec/javascripts/up/classes/store/session_spec.js.coffee +3 -2
  151. data/spec_app/spec/javascripts/up/element_spec.coffee +897 -0
  152. data/spec_app/spec/javascripts/up/event_spec.js.coffee +496 -0
  153. data/spec_app/spec/javascripts/up/feedback_spec.js.coffee +69 -48
  154. data/spec_app/spec/javascripts/up/form_spec.js.coffee +252 -194
  155. data/spec_app/spec/javascripts/up/{dom_spec.js.coffee → fragment_spec.js.coffee} +381 -388
  156. data/spec_app/spec/javascripts/up/history_spec.js.coffee +21 -19
  157. data/spec_app/spec/javascripts/up/jquery_spec.js.coffee +4 -0
  158. data/spec_app/spec/javascripts/up/legacy_spec.js.coffee +27 -0
  159. data/spec_app/spec/javascripts/up/link_spec.js.coffee +163 -160
  160. data/spec_app/spec/javascripts/up/log_spec.js.coffee +85 -12
  161. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +141 -123
  162. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +117 -113
  163. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +60 -77
  164. data/spec_app/spec/javascripts/up/protocol_spec.js.coffee +1 -0
  165. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +85 -78
  166. data/spec_app/spec/javascripts/up/radio_spec.js.coffee +29 -22
  167. data/spec_app/spec/javascripts/up/rails_spec.js.coffee +14 -13
  168. data/spec_app/spec/javascripts/up/spec_spec.js.coffee +9 -0
  169. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +96 -66
  170. data/spec_app/spec/javascripts/up/toast_spec.js.coffee +37 -0
  171. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +31 -47
  172. data/spec_app/spec/javascripts/up/util_spec.js.coffee +725 -562
  173. data/spec_app/spec/javascripts/up/{layout_spec.js.coffee → viewport_spec.js.coffee} +175 -149
  174. metadata +57 -19
  175. data/lib/assets/javascripts/unpoly-bootstrap3/layout-ext.coffee +0 -5
  176. data/lib/assets/javascripts/unpoly/bus.coffee.erb +0 -518
  177. data/lib/assets/javascripts/unpoly/classes/extract_step.coffee +0 -4
  178. data/lib/assets/javascripts/unpoly/classes/motion_tracker.coffee +0 -125
  179. data/lib/assets/javascripts/unpoly/params.coffee.erb +0 -522
  180. data/spec_app/spec/javascripts/helpers/append_fixture.js.coffee +0 -8
  181. data/spec_app/spec/javascripts/up/bus_spec.js.coffee +0 -210
  182. data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +0 -9
  183. data/spec_app/spec/javascripts/up/params_spec.coffee +0 -768
  184. data/spec_app/vendor/asset-libs/jasmine-fixture-1.3.4/jasmine-fixture.js +0 -433
  185. data/spec_app/vendor/asset-libs/jasmine-jquery-2.1.1/.bower.json +0 -26
  186. data/spec_app/vendor/asset-libs/jasmine-jquery-2.1.1/jasmine-jquery.js +0 -838
@@ -0,0 +1,67 @@
1
+ ###**
2
+ @module up.framework
3
+ ###
4
+
5
+ up.framework = do ->
6
+
7
+ u = up.util
8
+
9
+ isBooting = true
10
+
11
+ ###**
12
+ Resets Unpoly to the state when it was booted.
13
+ All custom event handlers, animations, etc. that have been registered
14
+ will be discarded.
15
+
16
+ Emits event [`up:framework:reset`](/up:framework:reset).
17
+
18
+ @function up.framework.reset
19
+ @internal
20
+ ###
21
+ emitReset = ->
22
+ up.emit('up:framework:reset', log: 'Resetting framework')
23
+
24
+ ###**
25
+ This event is [emitted](/up.emit) when Unpoly is [reset](/up.framework.reset) during unit tests.
26
+
27
+ @event up:framework:reset
28
+ @internal
29
+ ###
30
+
31
+ ###**
32
+ Boots the Unpoly framework.
33
+
34
+ **This is called automatically** by including the Unpoly JavaScript files.
35
+
36
+ Unpoly will not boot if the current browser is [not supported](/up.browser.isSupported).
37
+ This leaves you with a classic server-side application on legacy browsers.
38
+
39
+ @function up.boot
40
+ @internal
41
+ ###
42
+ boot = ->
43
+ if up.browser.isSupported()
44
+ # This is called synchronously after all Unpoly modules have been parsed
45
+ # and executed. User code hasn't been executed yet. Use this moment to
46
+ # tell everyone to snapshot
47
+ up.emit('up:framework:booted', log: 'Framework booted')
48
+ isBooting = false
49
+
50
+ # From here on, all event handlers (both Unpoly's and user code) should be able
51
+ # to work with the DOM, so wait for the DOM to be ready.
52
+ up.event.onReady ->
53
+ # In case the DOM was already ready when up.event.boot() was called, we still
54
+ # haven't executed user-provided code. So we wait one more frame until
55
+ # user-provided compilers, event handlers, etc. have been registered.
56
+ # This also gives async user-code a chance to run in the next microtask.
57
+ u.task ->
58
+ # At this point all user-code has been called.
59
+ # The following event will cause Unpoly to compile the <body>.
60
+ up.emit('up:app:boot', log: 'Booting user application')
61
+ up.emit('up:app:booted', log: 'User application booted')
62
+ else
63
+ console.log?("Unpoly doesn't support this browser. Framework was not booted.")
64
+
65
+ reset: emitReset
66
+ boot: boot
67
+ isBooting: -> isBooting
@@ -6,11 +6,12 @@ In an Unpoly app, every page has an URL.
6
6
 
7
7
  [Fragment updates](/up.link) automatically update the URL.
8
8
 
9
- @class up.history
9
+ @module up.history
10
10
  ###
11
- up.history = (($) ->
11
+ up.history = do ->
12
12
 
13
13
  u = up.util
14
+ e = up.element
14
15
 
15
16
  ###**
16
17
  Configures behavior when the user goes back or forward in browser history.
@@ -24,7 +25,7 @@ up.history = (($) ->
24
25
  when the user goes back or forward in history.
25
26
  @stable
26
27
  ###
27
- config = u.config
28
+ config = new up.Config
28
29
  enabled: true
29
30
  popTargets: ['body']
30
31
  restoreScroll: true
@@ -119,11 +120,11 @@ up.history = (($) ->
119
120
  push = (url, options) ->
120
121
  options = u.options(options, force: false)
121
122
  url = normalizeUrl(url)
122
- if (options.force || !isCurrentUrl(url)) && up.bus.nobodyPrevents('up:history:push', url: url, message: "Adding history entry for #{url}")
123
+ if (options.force || !isCurrentUrl(url)) && up.event.nobodyPrevents('up:history:push', url: url, log: "Adding history entry for #{url}")
123
124
  if manipulate('pushState', url)
124
- up.emit('up:history:pushed', url: url, message: "Advanced to location #{url}")
125
+ up.emit('up:history:pushed', url: url, log: "Advanced to location #{url}")
125
126
  else
126
- up.emit('up:history:muted', url: url, message: "Did not advance to #{url} (history is unavailable)")
127
+ up.emit('up:history:muted', url: url, log: "Did not advance to #{url} (history is unavailable)")
127
128
 
128
129
  ###**
129
130
  This event is [emitted](/up.emit) before a new history entry is added.
@@ -162,27 +163,26 @@ up.history = (($) ->
162
163
  url = currentUrl()
163
164
 
164
165
  # We can't let people prevent this event, since `popstate` is also unpreventable.
165
- up.emit('up:history:restore', url: url, message: "Restoring location #{url}")
166
+ up.emit('up:history:restore', url: url, log: "Restoring location #{url}")
166
167
 
167
168
  popSelector = config.popTargets.join(', ')
168
169
  replaced = up.replace popSelector, url,
169
170
  history: false, # don't push a new state
170
171
  title: true, # do extract the title from the response
171
172
  reveal: false,
172
- transition: 'none',
173
173
  saveScroll: false # since the URL was already changed by the browser, don't save scroll state
174
174
  restoreScroll: config.restoreScroll
175
175
  layer: 'page' # Don't replace elements in a modal that might still be open
176
176
  replaced.then ->
177
177
  url = currentUrl()
178
- up.emit('up:history:restored', url: url, message: "Restored location #{url}")
178
+ up.emit('up:history:restored', url: url, log: "Restored location #{url}")
179
179
  else
180
180
  up.puts 'Ignoring a state not pushed by Unpoly (%o)', state
181
181
 
182
182
  pop = (event) ->
183
183
  observeNewUrl(currentUrl())
184
- up.layout.saveScroll(url: previousUrl)
185
- state = event.originalEvent.state
184
+ up.viewport.saveScroll(url: previousUrl)
185
+ state = event.state
186
186
  restoreStateOnPop(state)
187
187
 
188
188
  ###**
@@ -207,19 +207,21 @@ up.history = (($) ->
207
207
  @experimental
208
208
  ###
209
209
 
210
- if up.browser.canPushState()
211
- register = ->
212
- $(window).on "popstate", pop
213
- replace(currentUrl(), force: true)
210
+ up.on 'up:app:boot', ->
211
+ if up.browser.canPushState()
212
+ register = ->
213
+ window.history.scrollRestoration = 'manual' if up.browser.canControlScrollRestoration()
214
+ window.addEventListener('popstate', pop)
215
+ replace(currentUrl(), force: true)
214
216
 
215
- if jasmine?
216
- # Can't delay this in tests.
217
- register()
218
- else
219
- # Defeat an unnecessary popstate that some browsers trigger
220
- # on pageload (Safari, Chrome < 34).
221
- # We should check in 2023 if we can remove this.
222
- setTimeout register, 100
217
+ if jasmine?
218
+ # Can't delay this in tests.
219
+ register()
220
+ else
221
+ # Defeat an unnecessary popstate that some browsers trigger
222
+ # on pageload (Safari, Chrome < 34).
223
+ # We should check in 2023 if we can remove this.
224
+ setTimeout(register, 100)
223
225
 
224
226
  ###**
225
227
  Changes the link's destination so it points to the previous URL.
@@ -246,13 +248,13 @@ up.history = (($) ->
246
248
  @selector a[up-back]
247
249
  @stable
248
250
  ###
249
- up.macro 'a[up-back], [up-href][up-back]', ($link) ->
251
+ up.macro 'a[up-back], [up-href][up-back]', (link) ->
250
252
  if u.isPresent(previousUrl)
251
- u.setMissingAttrs $link,
253
+ e.setMissingAttrs link,
252
254
  'up-href': previousUrl,
253
255
  'up-restore-scroll': ''
254
- $link.removeAttr 'up-back'
255
- up.link.makeFollowable($link)
256
+ link.removeAttribute('up-back')
257
+ up.link.makeFollowable(link)
256
258
 
257
259
  up.on 'up:framework:reset', reset
258
260
 
@@ -264,4 +266,3 @@ up.history = (($) ->
264
266
  previousUrl: -> previousUrl
265
267
  normalizeUrl: normalizeUrl
266
268
 
267
- )(jQuery)
@@ -0,0 +1,60 @@
1
+ u = up.util
2
+
3
+ up.legacy = do ->
4
+
5
+ # renamedProperty = (object, oldKey, newKey) ->
6
+ # warning = -> warn('Property { %s } has been renamed to { %s } (found in %o)', oldKey, newKey, object)
7
+ # Object.defineProperty object, oldKey,
8
+ # get: ->
9
+ # warning()
10
+ # @[newKey]
11
+ # set: (newValue) ->
12
+ # warning()
13
+ # @[newKey] = newValue
14
+
15
+ # removedProperty = (object, key) ->
16
+ # failure = -> up.fail('Deprecated: Property { %s } is no longer supported (found in %o)', key, object)
17
+ # Object.defineProperty object, key,
18
+ # get: failure
19
+ # set: failure
20
+
21
+ fixKey = (object, oldKey, newKey) ->
22
+ if oldKey of object
23
+ warn('Property { %s } has been renamed to { %s } (found in %o)', oldKey, newKey, object)
24
+ u.renameKey(object, oldKey, newKey)
25
+
26
+ # # Maps old event name to new event name
27
+ # renamedEvents = {}
28
+ #
29
+ # renamedEvent = (oldName, newName) ->
30
+ # renamedEvents[oldName] = newName
31
+ #
32
+ # fixEventName = (eventName) ->
33
+ # if newEventName = renamedEvents[eventName]
34
+ # warn("Event #{eventName} has been renamed to #{newEventName}")
35
+ # newEventName
36
+ # else
37
+ # eventName
38
+
39
+ renamedModule = (oldName, newName) ->
40
+ Object.defineProperty up, oldName, get: ->
41
+ warn("up.#{oldName} has been renamed to up.#{newName}")
42
+ up[newName]
43
+
44
+ warnedMessages = {}
45
+
46
+ warn = (message, args...) ->
47
+ message = "[DEPRECATION] #{message}"
48
+ message = up.log.sprintf(message, args...)
49
+ unless warnedMessages[message]
50
+ warnedMessages[message] = true
51
+ up.warn(message)
52
+
53
+ renamedModule: renamedModule
54
+ # renamedProperty: renamedProperty
55
+ # removedProperty: removedProperty
56
+ # renamedEvent: renamedEvent
57
+ # fixEventName: fixEventName
58
+ fixKey: fixKey
59
+ warn: warn
60
+
@@ -2,6 +2,10 @@
2
2
  Linking to fragments
3
3
  ====================
4
4
 
5
+ The `up.link` module lets you build links that update fragments instead of entire pages.
6
+
7
+ \#\#\# Motivation
8
+
5
9
  In a traditional web application, the entire page is destroyed and re-created when the
6
10
  user follows a link:
7
11
 
@@ -29,7 +33,7 @@ Pages also load much faster since the DOM, CSS and Javascript environments do no
29
33
  destroyed and recreated for every request.
30
34
 
31
35
 
32
- ## Example
36
+ \#\#\# Example
33
37
 
34
38
  Let's say we are rendering three pages with a tabbed navigation to switch between screens:
35
39
 
@@ -64,19 +68,21 @@ With these [`up-target`](/a-up-target) annotations Unpoly only updates the targe
64
68
  The JavaScript environment will persist and the user will not see a white flash while the
65
69
  new page is loading.
66
70
 
67
- @class up.link
71
+ @module up.link
68
72
  ###
69
73
 
70
- up.link = (($) ->
74
+ up.link = do ->
71
75
 
72
76
  u = up.util
77
+ e = up.element
73
78
 
74
79
  ###**
75
- Visits the given URL without a full page load.
76
- This is done by fetching `url` through an AJAX request
77
- and [replacing](/up.replace) the current `<body>` element with the response's `<body>` element.
80
+ Fetches this given URL with JavaScript and [replaces](/up.replace) the
81
+ current `<body>` element with the response's `<body>` element.
78
82
 
79
- For example, this would fetch the `/users` URL:
83
+ \#\#\# Example
84
+
85
+ This would replace the current page with the response for `/users`:
80
86
 
81
87
  up.visit('/users')
82
88
 
@@ -89,37 +95,34 @@ up.link = (($) ->
89
95
  See options for [`up.replace()`](/up.replace)
90
96
  @stable
91
97
  ###
92
- visit = (url, options) ->
93
- options = u.options(options)
94
- selector = u.option(options.target, 'body')
98
+ visit = (url, options = {}) ->
99
+ selector = options.target ? 'body'
95
100
  up.replace(selector, url, options)
96
101
 
97
102
  ###**
98
- Follows the given link via AJAX and [replaces](/up.replace) the current page
99
- with HTML from the response.
103
+ Fetches the given link's `[href]` with JavaScript and [replaces](/up.replace) the current page with HTML from the response.
100
104
 
101
105
  By default the page's `<body>` element will be replaced.
102
- If the link has an attribute like [`[up-target]`](/up-target)
103
- or [`[up-modal]`](/a-up-modal), the corresponding UJS behavior will be activated
104
- just as if the user had clicked on the link.
106
+ If the link has an attribute like `a[up-target]`
107
+ or `a[up-modal]`, the respective Unpoly behavior will be used.
105
108
 
106
- Emits the event [`up:link:follow`](/up:link:follow).
109
+ Emits the event `up:link:follow`.
107
110
 
108
111
  \#\#\# Examples
109
112
 
110
- Let's say you have a link with an [`a[up-target]`](/a-up-target) attribute:
113
+ Assume we have a link with an `a[up-target]` attribute:
111
114
 
112
115
  <a href="/users" up-target=".main">Users</a>
113
116
 
114
117
  Calling `up.follow()` with this link will replace the page's `.main` fragment
115
118
  as if the user had clicked on the link:
116
119
 
117
- var $link = $('a:first');
118
- up.follow($link);
120
+ var link = document.querSelector('a')
121
+ up.follow(link)
119
122
 
120
123
  @function up.follow
121
124
  @param {Element|jQuery|string} linkOrSelector
122
- An element or selector which is either an `<a>` tag or any element with an `up-href` attribute.
125
+ An element or selector which is either an `<a>` tag or any element with an `[up-href]` attribute.
123
126
  @param {string} [options.target]
124
127
  The selector to replace.
125
128
 
@@ -143,9 +146,9 @@ up.link = (($) ->
143
146
  @stable
144
147
  ###
145
148
  follow = (linkOrSelector, options) ->
146
- $link = $(linkOrSelector)
147
- variant = followVariantForLink($link)
148
- variant.followLink($link, options)
149
+ link = e.get(linkOrSelector)
150
+ variant = followVariantForLink(link)
151
+ variant.followLink(link, options)
149
152
 
150
153
  ###**
151
154
  This event is [emitted](/up.emit) when a link is [followed](/up.follow) through Unpoly.
@@ -153,7 +156,7 @@ up.link = (($) ->
153
156
  The event is emitted on the `<a>` element that is being followed.
154
157
 
155
158
  @event up:link:follow
156
- @param {jQuery} event.$link
159
+ @param {Element} event.target
157
160
  The link element that will be followed.
158
161
  @param event.preventDefault()
159
162
  Event listeners may call this method to prevent the link from being followed.
@@ -164,36 +167,33 @@ up.link = (($) ->
164
167
  @function defaultFollow
165
168
  @internal
166
169
  ###
167
- defaultFollow = (linkOrSelector, options) ->
168
- $link = $(linkOrSelector)
169
-
170
+ defaultFollow = (link, options) ->
170
171
  options = u.options(options)
171
-
172
- url = u.option(options.url, $link.attr('up-href'), $link.attr('href'))
173
- target = u.option(options.target, $link.attr('up-target'))
174
- options.failTarget = u.option(options.failTarget, $link.attr('up-fail-target'))
175
- options.fallback = u.option(options.fallback, $link.attr('up-fallback'))
176
- options.transition = u.option(options.transition, u.castedAttr($link, 'up-transition'), 'none')
177
- options.failTransition = u.option(options.failTransition, u.castedAttr($link, 'up-fail-transition'), 'none')
178
- options.history = u.option(options.history, u.castedAttr($link, 'up-history'))
179
- options.reveal = u.option(options.reveal, u.castedAttr($link, 'up-reveal'), true)
180
- options.failReveal = u.option(options.failReveal, u.castedAttr($link, 'up-fail-reveal'), true)
181
- options.cache = u.option(options.cache, u.castedAttr($link, 'up-cache'))
182
- options.restoreScroll = u.option(options.restoreScroll, u.castedAttr($link, 'up-restore-scroll'))
183
- options.method = followMethod($link, options)
184
- options.origin = u.option(options.origin, $link)
185
- options.layer = u.option(options.layer, $link.attr('up-layer'), 'auto')
186
- options.failLayer = u.option(options.failLayer, $link.attr('up-fail-layer'), 'auto')
187
- options.confirm = u.option(options.confirm, $link.attr('up-confirm'))
188
- options = u.merge(options, up.motion.animateOptions(options, $link))
172
+ url = options.url ? link.getAttribute('up-href') ? link.getAttribute('href')
173
+ target = options.target ? link.getAttribute('up-target')
174
+ options.failTarget ?= link.getAttribute('up-fail-target')
175
+ options.fallback ?= link.getAttribute('up-fallback')
176
+ options.transition ?= e.booleanOrStringAttr(link, 'up-transition')
177
+ options.failTransition ?= e.booleanOrStringAttr(link, 'up-fail-transition')
178
+ options.history ?= e.booleanOrStringAttr(link, 'up-history')
179
+ options.reveal ?= e.booleanOrStringAttr(link, 'up-reveal') ? true
180
+ options.failReveal ?= e.booleanOrStringAttr(link, 'up-fail-reveal') ? true
181
+ options.cache ?= e.booleanAttr(link, 'up-cache')
182
+ options.restoreScroll ?= e.booleanAttr(link, 'up-restore-scroll') # the option may contain an Object, but not the attr
183
+ options.method = followMethod(link, options)
184
+ options.origin ?= link
185
+ options.layer ?= link.getAttribute('up-layer')
186
+ options.failLayer ?= link.getAttribute('up-fail-layer')
187
+ options.confirm ?= link.getAttribute('up-confirm')
188
+ options = u.merge(options, up.motion.animateOptions(options, link))
189
189
 
190
190
  up.browser.whenConfirmed(options).then ->
191
191
  up.replace(target, url, options)
192
192
 
193
- defaultPreload = ($link, options) ->
193
+ defaultPreload = (link, options) ->
194
194
  options = u.options(options)
195
195
  options.preload = true
196
- defaultFollow($link, options)
196
+ defaultFollow(link, options)
197
197
 
198
198
  ###**
199
199
  Returns the HTTP method that should be used when following the given link.
@@ -202,14 +202,13 @@ up.link = (($) ->
202
202
  Defaults to `"get"`.
203
203
 
204
204
  @function up.link.followMethod
205
- @param linkOrSelector
205
+ @param link
206
206
  @param options.method {string}
207
207
  @internal
208
208
  ###
209
- followMethod = (linkOrSelector, options) ->
210
- $link = $(linkOrSelector)
211
- options = u.options(options)
212
- u.option(options.method, $link.attr('up-method'), $link.attr('data-method'), 'get').toUpperCase()
209
+ followMethod = (link, options = {}) ->
210
+ rawMethod = options.method ? link.getAttribute('up-method') ? link.getAttribute('data-method') ? 'GET'
211
+ rawMethod.toUpperCase()
213
212
 
214
213
  ###**
215
214
  No-op that is called when we allow a browser's default action to go through,
@@ -233,8 +232,8 @@ up.link = (($) ->
233
232
  @function up.link.addFollowVariant
234
233
  @param {string} simplifiedSelector
235
234
  A selector without `a` or `[up-href]`, e.g. `[up-target]`
236
- @param {Function(jQuery, Object)} options.follow
237
- @param {Function(jQuery, Object)} options.preload
235
+ @param {Function(element, options)} options.follow
236
+ @param {Function(element, options)} options.preload
238
237
  @internal
239
238
  ###
240
239
  addFollowVariant = (simplifiedSelector, options) ->
@@ -244,40 +243,41 @@ up.link = (($) ->
244
243
  variant
245
244
 
246
245
  ###**
247
- Returns whether the given link will be handled by Unpoly instead of making a full page load.
246
+ Returns whether the given link will be [followed](/up.follow) by Unpoly
247
+ instead of making a full page load.
248
248
 
249
- A link will be handled by Unpoly if it has an attribute
250
- like `up-target` or `up-modal`.
249
+ A link will be followed by Unpoly if it has an attribute
250
+ like `a[up-target]` or `a[up-modal]`.
251
251
 
252
252
  @function up.link.isFollowable
253
253
  @param {Element|jQuery|string} linkOrSelector
254
254
  The link to check.
255
255
  @experimental
256
256
  ###
257
- isFollowable = (link) ->
258
- !!followVariantForLink(link, default: false)
257
+ isFollowable = (linkOrSelector) ->
258
+ linkOrSelector = e.get(linkOrSelector)
259
+ !!followVariantForLink(linkOrSelector, default: false)
259
260
 
260
261
  ###**
261
262
  Returns the handler function that can be used to follow the given link.
262
263
  E.g. it wil return a handler calling `up.modal.follow` if the link is a `[up-modal]`,
263
264
  but a handler calling `up.link.follow` if the links is `[up-target]`.
264
265
 
265
- @param {Element|jQuery|string}
266
- @return {Function(jQuery)}
266
+ @param {Element} link
267
+ @return {Object}
267
268
  @internal
268
269
  ###
269
- followVariantForLink = (linkOrSelector, options) ->
270
- options = u.options(options)
271
- $link = $(linkOrSelector)
272
- variant = u.detect followVariants, (variant) -> variant.matchesLink($link)
270
+ followVariantForLink = (link, options = {}) ->
271
+ variant = u.find followVariants, (variant) -> variant.matchesLink(link)
273
272
  variant ||= DEFAULT_FOLLOW_VARIANT unless options.default is false
274
273
  variant
275
274
 
276
275
  ###**
277
- Makes sure that the given link will be handled by Unpoly instead of making a full page load.
276
+ Makes sure that the given link will be [followed](/up.follow)
277
+ by Unpoly instead of making a full page load.
278
278
 
279
- This is done by giving the link an `up-follow` attribute
280
- unless it already have it an attribute like `up-target` or `up-modal`.
279
+ This is done by giving the link an `a[up-follow]` attribute
280
+ unless it already have it an attribute like `a[up-target]` or `a[up-modal]`.
281
281
 
282
282
  @function up.link.makeFollowable
283
283
  @param {Element|jQuery|string} linkOrSelector
@@ -285,21 +285,20 @@ up.link = (($) ->
285
285
  @experimental
286
286
  ###
287
287
  makeFollowable = (link) ->
288
- $link = $(link)
289
- unless isFollowable($link)
290
- $link.attr('up-follow', '')
288
+ unless isFollowable(link)
289
+ link.setAttribute('up-follow', '')
291
290
 
292
- shouldProcessEvent = (event, $link) ->
291
+ shouldProcessEvent = (event, link) ->
293
292
  target = event.target
294
293
  # We never handle events for the right mouse button, or when Shift/CTRL/Meta is pressed
295
294
  return false unless u.isUnmodifiedMouseEvent(event)
296
- # If we actually targeted $link, save ourselves the expensive DOM traversal below
297
- return true if target == $link.get(0)
295
+ # If we actually targeted `link`, save ourselves the expensive DOM traversal below
296
+ return true if target == link
298
297
  # If user clicked on a child link of $link, or in an <input> within an [up-expand][up-href]
299
298
  # we want those other elements handle the click.
300
- $betterTarget = $(target).closest("a, [up-href], #{up.form.fieldSelector()}").not($link)
301
- return false if $betterTarget.length
302
- return true
299
+ betterTargetSelector = "a, [up-href], #{up.form.fieldSelector()}"
300
+ betterTarget = e.closest(target, betterTargetSelector)
301
+ return !betterTarget || betterTarget == link
303
302
 
304
303
  ###**
305
304
  Returns whether the given link has a [safe](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1)
@@ -309,20 +308,26 @@ up.link = (($) ->
309
308
  @experimental
310
309
  ###
311
310
  isSafe = (selectorOrLink, options) ->
312
- $link = $(selectorOrLink)
313
- method = followMethod($link, options)
311
+ method = followMethod(selectorOrLink, options)
314
312
  up.proxy.isSafeMethod(method)
315
313
 
316
314
  ###**
317
- Follows this link via AJAX and replaces a CSS selector in the current page
318
- with corresponding elements from a new page fetched from the server:
315
+ [Follows](/up.follow) this link with JavaScript and replaces a CSS selector
316
+ on the current page with a corresponding element from the response.
317
+
318
+ \#\#\# Example
319
+
320
+ This will update the fragment `<div class="main">` with the same element
321
+ fetched from `/posts/5`:
319
322
 
320
323
  <a href="/posts/5" up-target=".main">Read post</a>
321
324
 
322
325
  \#\#\# Updating multiple fragments
323
326
 
324
327
  You can update multiple fragments from a single request by separating
325
- separators with a comma (like in CSS). E.g. if opening a post should
328
+ separators with a comma (like in CSS).
329
+
330
+ For instance, if opening a post should
326
331
  also update a bubble showing the number of unread posts, you might
327
332
  do this:
328
333
 
@@ -331,7 +336,7 @@ up.link = (($) ->
331
336
  \#\#\# Appending or prepending content
332
337
 
333
338
  By default Unpoly will replace the given selector with the same
334
- selector from a freshly fetched page. Instead of replacing you
339
+ selector from the server response. Instead of replacing you
335
340
  can *append* the loaded content to the existing content by using the
336
341
  `:after` pseudo selector. In the same fashion, you can use `:before`
337
342
  to indicate that you would like the *prepend* the loaded content.
@@ -353,7 +358,7 @@ up.link = (($) ->
353
358
  \#\#\# Following elements that are no links
354
359
 
355
360
  You can also use `[up-target]` to turn an arbitrary element into a link.
356
- In this case, put the link's destination into the `up-href` attribute:
361
+ In this case, put the link's destination into the `[up-href]` attribute:
357
362
 
358
363
  <button up-target=".main" up-href="/foo/bar">Go</button>
359
364
 
@@ -420,15 +425,14 @@ up.link = (($) ->
420
425
  ###
421
426
  DEFAULT_FOLLOW_VARIANT = addFollowVariant '[up-target], [up-follow]',
422
427
  # Don't just pass the `defaultFollow` function reference so we can stub it in tests
423
- follow: ($link, options) -> defaultFollow($link, options)
424
- preload: ($link, options) -> defaultPreload($link, options)
428
+ follow: (link, options) -> defaultFollow(link, options)
429
+ preload: (link, options) -> defaultPreload(link, options)
425
430
 
426
431
  ###**
427
- If applied on a link, follows this link via AJAX and replaces the
432
+ Fetches this link's `[href]` with JavaScript and [replaces](/up.replace) the
428
433
  current `<body>` element with the response's `<body>` element.
429
434
 
430
- To only update a fragment instead of the entire page, see
431
- [`a[up-target]`](/a-up-target).
435
+ To only update a fragment instead of the entire `<body>`, see `a[up-target]`.
432
436
 
433
437
  \#\#\# Example
434
438
 
@@ -485,19 +489,19 @@ up.link = (($) ->
485
489
  AJAX request will be triggered right way, the interaction will
486
490
  appear faster.
487
491
 
488
- Note that using `[up-instant]` will prevent a user from canceling a link
489
- click by moving the mouse away from the interaction area. However, for
492
+ Note that using `[up-instant]` will prevent a user from canceling a
493
+ click by moving the mouse away from the link. However, for
490
494
  navigation actions this isn't needed. E.g. popular operation
491
495
  systems switch tabs on `mousedown` instead of `click`.
492
496
 
493
- `up-instant` will also work for links that open [modals](/up.modal) or [popups](/up.popup).
497
+ `[up-instant]` will also work for links that open [modals](/up.modal) or [popups](/up.popup).
494
498
 
495
499
  @selector a[up-instant]
496
500
  @stable
497
501
  ###
498
502
 
499
503
  ###**
500
- Marks up the current link to be followed *as fast as possible*.
504
+ [Follows](/up.follow) this link *as fast as possible*.
501
505
 
502
506
  This is done by:
503
507
 
@@ -505,20 +509,26 @@ up.link = (($) ->
505
509
  - [Preloading the link's destination URL](/a-up-preload)
506
510
  - [Triggering the link on `mousedown`](/a-up-instant) instead of on `click`
507
511
 
512
+ \#\#\# Example
513
+
508
514
  Use `up-dash` like this:
509
515
 
510
516
  <a href="/users" up-dash=".main">User list</a>
511
517
 
512
- Note that this is shorthand for:
518
+ This is shorthand for:
513
519
 
514
520
  <a href="/users" up-target=".main" up-instant up-preload>User list</a>
515
521
 
516
522
  @selector a[up-dash]
523
+ @param {string} [up-dash='body']
524
+ The CSS selector to replace
525
+
526
+ Inside the CSS selector you may refer to this link as `&` ([like in Sass](https://sass-lang.com/documentation/file.SASS_REFERENCE.html#parent-selector)).
517
527
  @stable
518
528
  ###
519
- up.macro '[up-dash]', ($element) ->
520
- target = u.castedAttr($element, 'up-dash')
521
- $element.removeAttr('up-dash')
529
+ up.macro '[up-dash]', (element) ->
530
+ target = e.booleanOrStringAttr(element, 'up-dash')
531
+ element.removeAttribute('up-dash')
522
532
  newAttrs = {
523
533
  'up-preload': '',
524
534
  'up-instant': ''
@@ -526,17 +536,19 @@ up.link = (($) ->
526
536
  if target is true
527
537
  # If it's literally `true` then we don't have a target selector.
528
538
  # Just follow the link by replacing `<body>`.
529
- makeFollowable($element)
539
+ makeFollowable(element)
530
540
  else
531
541
  newAttrs['up-target'] = target
532
- u.setMissingAttrs($element, newAttrs)
542
+ e.setMissingAttrs(element, newAttrs)
533
543
 
534
544
  ###**
535
- Add an `[up-expand]` attribute to any element that contains a link
536
- in order to enlarge the link's click area.
545
+ Add an `[up-expand]` attribute to any element to enlarge the click area of an
546
+ descendant link.
547
+
548
+ `[up-expand]` honors all the Unppoly attributes in expanded links, like
549
+ `a[up-target]`, `a[up-instant]` or `a[up-preload]`.
550
+ It also expands links that open [modals](/up.modal) or [popups](/up.popup).
537
551
 
538
- `[up-expand]` honors all the UJS behavior in expanded links
539
- ([`a[up-target]`](/a-up-target), [`a[up-instant]`](/a-up-instant), [`a[up-preload]`](/a-up-preload), etc.).
540
552
 
541
553
  \#\#\# Example
542
554
 
@@ -548,8 +560,6 @@ up.link = (($) ->
548
560
  In the example above, clicking anywhere within `.notification` element
549
561
  would [follow](/up.follow) the *Close* link.
550
562
 
551
- `up-expand` also expands links that open [modals](/up.modal) or [popups](/up.popup).
552
-
553
563
  \#\#\# Elements with multiple contained links
554
564
 
555
565
  If a container contains more than one link, you can set the value of the
@@ -566,7 +576,7 @@ up.link = (($) ->
566
576
  `[up-expand]` has some limitations for advanced browser users:
567
577
 
568
578
  - Users won't be able to right-click the expanded area to open a context menu
569
- - Users won't be able to CTRL+click the expanded area to open a new tab
579
+ - Users won't be able to `CTRL`+click the expanded area to open a new tab
570
580
 
571
581
  To overcome these limitations, consider nesting the entire clickable area in an actual `<a>` tag.
572
582
  [It's OK to put block elements inside an anchor tag](https://makandracards.com/makandra/43549-it-s-ok-to-put-block-elements-inside-an-a-tag).
@@ -575,24 +585,24 @@ up.link = (($) ->
575
585
  @param {string} [up-expand]
576
586
  A CSS selector that defines which containing link should be expanded.
577
587
 
578
- If omitted, the first contained link will be expanded.
588
+ If omitted, the first link in this element will be expanded.
579
589
  @stable
580
590
  ###
581
- up.macro '[up-expand]', ($area) ->
582
- $childLinks = $area.find('a, [up-href]')
583
- if selector = $area.attr('up-expand')
584
- $childLinks = $childLinks.filter(selector)
585
- if link = $childLinks.get(0)
591
+ up.macro '[up-expand]', (area) ->
592
+ selector = area.getAttribute('up-expand') || 'a, [up-href]'
593
+ childLinks = e.all(area, selector)
594
+
595
+ if childLink = childLinks[0]
586
596
  upAttributePattern = /^up-/
587
597
  newAttrs = {}
588
- newAttrs['up-href'] = $(link).attr('href')
589
- for attribute in link.attributes
598
+ newAttrs['up-href'] = childLink.getAttribute('href')
599
+ for attribute in childLink.attributes
590
600
  name = attribute.name
591
601
  if name.match(upAttributePattern)
592
602
  newAttrs[name] = attribute.value
593
- u.setMissingAttrs($area, newAttrs)
594
- $area.removeAttr('up-expand')
595
- makeFollowable($area)
603
+ e.setMissingAttrs(area, newAttrs)
604
+ area.removeAttribute('up-expand')
605
+ makeFollowable(area)
596
606
 
597
607
  <% if ENV['JS_KNIFE'] %>knife: eval(Knife.point)<% end %>
598
608
  visit: visit
@@ -606,7 +616,5 @@ up.link = (($) ->
606
616
  followVariantForLink: followVariantForLink
607
617
  allowDefault: allowDefault
608
618
 
609
- )(jQuery)
610
-
611
619
  up.visit = up.link.visit
612
620
  up.follow = up.link.follow