unpoly-rails 0.61.0 → 2.0.0.pre.rc3

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 (340) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +94 -1
  4. data/README.md +3 -11
  5. data/README_RAILS.md +295 -14
  6. data/dist/unpoly-bootstrap3.css +9 -14
  7. data/dist/unpoly-bootstrap3.js +4 -18
  8. data/dist/unpoly-bootstrap3.min.css +1 -1
  9. data/dist/unpoly-bootstrap3.min.js +1 -1
  10. data/dist/unpoly-bootstrap4.css +9 -0
  11. data/dist/unpoly-bootstrap4.js +16 -0
  12. data/dist/unpoly-bootstrap4.min.css +1 -0
  13. data/dist/unpoly-bootstrap4.min.js +1 -0
  14. data/dist/unpoly-bootstrap5.css +9 -0
  15. data/dist/unpoly-bootstrap5.js +14 -0
  16. data/dist/unpoly-bootstrap5.min.css +1 -0
  17. data/dist/unpoly-bootstrap5.min.js +1 -0
  18. data/dist/unpoly-migrate.js +1213 -0
  19. data/dist/unpoly-migrate.min.js +1 -0
  20. data/dist/unpoly.css +109 -140
  21. data/dist/unpoly.js +15439 -10434
  22. data/dist/unpoly.min.css +1 -1
  23. data/dist/unpoly.min.js +6 -4
  24. data/lib/unpoly-rails.rb +9 -3
  25. data/lib/unpoly/rails/change.rb +372 -0
  26. data/lib/unpoly/rails/change/cache.rb +26 -0
  27. data/lib/unpoly/rails/change/context.rb +80 -0
  28. data/lib/unpoly/rails/change/field.rb +117 -0
  29. data/lib/unpoly/rails/change/field_definition.rb +74 -0
  30. data/lib/unpoly/rails/change/layer.rb +60 -0
  31. data/lib/unpoly/rails/controller.rb +47 -0
  32. data/lib/unpoly/rails/error.rb +5 -0
  33. data/lib/unpoly/rails/request_echo_headers.rb +2 -2
  34. data/lib/unpoly/rails/version.rb +1 -1
  35. data/lib/unpoly/tasks.rb +45 -0
  36. metadata +43 -314
  37. data/.gitignore +0 -10
  38. data/.ruby-version +0 -2
  39. data/Gemfile +0 -8
  40. data/Gemfile.lock +0 -45
  41. data/Rakefile +0 -144
  42. data/bower.json +0 -27
  43. data/design/animation-ghosting.txt +0 -72
  44. data/design/design.txt +0 -34
  45. data/design/draft.html.erb +0 -48
  46. data/design/draft.rb +0 -9
  47. data/design/es6.js +0 -32
  48. data/design/ghost-debugging.txt +0 -118
  49. data/design/homepage.txt +0 -236
  50. data/design/ie11.txt +0 -9
  51. data/design/measure_import_node.js +0 -330
  52. data/design/measure_jquery/element_list.js +0 -41
  53. data/design/measure_jquery/up.on_vs_addEventListener.js +0 -56
  54. data/design/positioning.txt +0 -28
  55. data/design/query-params-in-form-actions/cases.html +0 -125
  56. data/design/rename.txt +0 -0
  57. data/design/test_rejected_promise.txt +0 -5
  58. data/design/unpoly errors.txt +0 -19
  59. data/lib/assets/javascripts/unpoly-bootstrap3.coffee +0 -2
  60. data/lib/assets/javascripts/unpoly-bootstrap3/feedback-ext.coffee +0 -5
  61. data/lib/assets/javascripts/unpoly-bootstrap3/form-ext.coffee +0 -1
  62. data/lib/assets/javascripts/unpoly-bootstrap3/modal-ext.coffee +0 -14
  63. data/lib/assets/javascripts/unpoly-bootstrap3/viewport-ext.coffee +0 -5
  64. data/lib/assets/javascripts/unpoly.coffee +0 -28
  65. data/lib/assets/javascripts/unpoly/browser.coffee.erb +0 -236
  66. data/lib/assets/javascripts/unpoly/classes/body_shifter.coffee +0 -36
  67. data/lib/assets/javascripts/unpoly/classes/cache.coffee +0 -127
  68. data/lib/assets/javascripts/unpoly/classes/compile_pass.coffee +0 -93
  69. data/lib/assets/javascripts/unpoly/classes/config.coffee +0 -9
  70. data/lib/assets/javascripts/unpoly/classes/css_transition.coffee +0 -118
  71. data/lib/assets/javascripts/unpoly/classes/divertible_chain.coffee +0 -39
  72. data/lib/assets/javascripts/unpoly/classes/event_listener.coffee +0 -116
  73. data/lib/assets/javascripts/unpoly/classes/extract_cascade.coffee +0 -86
  74. data/lib/assets/javascripts/unpoly/classes/extract_plan.coffee +0 -111
  75. data/lib/assets/javascripts/unpoly/classes/field_observer.coffee +0 -80
  76. data/lib/assets/javascripts/unpoly/classes/focus_follower.coffee +0 -29
  77. data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +0 -56
  78. data/lib/assets/javascripts/unpoly/classes/html_parser.coffee +0 -46
  79. data/lib/assets/javascripts/unpoly/classes/motion_controller.coffee +0 -157
  80. data/lib/assets/javascripts/unpoly/classes/params.coffee.erb +0 -543
  81. data/lib/assets/javascripts/unpoly/classes/record.coffee +0 -22
  82. data/lib/assets/javascripts/unpoly/classes/rect.js +0 -21
  83. data/lib/assets/javascripts/unpoly/classes/request.coffee +0 -246
  84. data/lib/assets/javascripts/unpoly/classes/response.coffee +0 -157
  85. data/lib/assets/javascripts/unpoly/classes/reveal_motion.coffee +0 -102
  86. data/lib/assets/javascripts/unpoly/classes/scroll_motion.coffee +0 -67
  87. data/lib/assets/javascripts/unpoly/classes/selector.coffee +0 -60
  88. data/lib/assets/javascripts/unpoly/classes/store/memory.coffee +0 -26
  89. data/lib/assets/javascripts/unpoly/classes/store/session.coffee +0 -59
  90. data/lib/assets/javascripts/unpoly/classes/tether.coffee +0 -105
  91. data/lib/assets/javascripts/unpoly/classes/url_set.coffee +0 -32
  92. data/lib/assets/javascripts/unpoly/cookie.coffee +0 -56
  93. data/lib/assets/javascripts/unpoly/element.coffee.erb +0 -1126
  94. data/lib/assets/javascripts/unpoly/event.coffee.erb +0 -438
  95. data/lib/assets/javascripts/unpoly/feedback.coffee +0 -353
  96. data/lib/assets/javascripts/unpoly/form.coffee.erb +0 -1032
  97. data/lib/assets/javascripts/unpoly/fragment.coffee.erb +0 -924
  98. data/lib/assets/javascripts/unpoly/framework.coffee +0 -67
  99. data/lib/assets/javascripts/unpoly/history.coffee +0 -268
  100. data/lib/assets/javascripts/unpoly/legacy.coffee +0 -60
  101. data/lib/assets/javascripts/unpoly/link.coffee.erb +0 -622
  102. data/lib/assets/javascripts/unpoly/log.coffee +0 -248
  103. data/lib/assets/javascripts/unpoly/modal.coffee.erb +0 -825
  104. data/lib/assets/javascripts/unpoly/motion.coffee.erb +0 -668
  105. data/lib/assets/javascripts/unpoly/namespace.coffee.erb +0 -5
  106. data/lib/assets/javascripts/unpoly/popup.coffee.erb +0 -515
  107. data/lib/assets/javascripts/unpoly/protocol.coffee +0 -298
  108. data/lib/assets/javascripts/unpoly/proxy.coffee +0 -672
  109. data/lib/assets/javascripts/unpoly/radio.coffee +0 -60
  110. data/lib/assets/javascripts/unpoly/rails.coffee +0 -24
  111. data/lib/assets/javascripts/unpoly/syntax.coffee.erb +0 -477
  112. data/lib/assets/javascripts/unpoly/toast.coffee +0 -67
  113. data/lib/assets/javascripts/unpoly/tooltip.coffee +0 -276
  114. data/lib/assets/javascripts/unpoly/util.coffee.erb +0 -1676
  115. data/lib/assets/javascripts/unpoly/viewport.coffee.erb +0 -806
  116. data/lib/assets/stylesheets/unpoly-bootstrap3.sass +0 -1
  117. data/lib/assets/stylesheets/unpoly-bootstrap3/modal-ext.sass +0 -27
  118. data/lib/assets/stylesheets/unpoly.sass +0 -1
  119. data/lib/assets/stylesheets/unpoly/close.sass +0 -2
  120. data/lib/assets/stylesheets/unpoly/dom.sass +0 -5
  121. data/lib/assets/stylesheets/unpoly/layout.sass +0 -2
  122. data/lib/assets/stylesheets/unpoly/link.sass +0 -2
  123. data/lib/assets/stylesheets/unpoly/modal.sass +0 -116
  124. data/lib/assets/stylesheets/unpoly/popup.sass +0 -7
  125. data/lib/assets/stylesheets/unpoly/toast.sass +0 -33
  126. data/lib/assets/stylesheets/unpoly/tooltip.sass +0 -62
  127. data/lib/unpoly/rails/inspector.rb +0 -149
  128. data/lib/unpoly/rails/inspector_accessor.rb +0 -30
  129. data/package.json +0 -38
  130. data/spec_app/.firefox-version +0 -1
  131. data/spec_app/.gitignore +0 -17
  132. data/spec_app/.rspec +0 -2
  133. data/spec_app/Gemfile +0 -32
  134. data/spec_app/Gemfile.lock +0 -233
  135. data/spec_app/README.rdoc +0 -28
  136. data/spec_app/Rakefile +0 -6
  137. data/spec_app/app/assets/images/.keep +0 -0
  138. data/spec_app/app/assets/images/favicon.png +0 -0
  139. data/spec_app/app/assets/images/grid.png +0 -0
  140. data/spec_app/app/assets/javascripts/bootstrap_manifest.coffee +0 -6
  141. data/spec_app/app/assets/javascripts/integration_test.coffee +0 -6
  142. data/spec_app/app/assets/javascripts/jasmine_specs.coffee +0 -6
  143. data/spec_app/app/assets/stylesheets/_helpers.sass +0 -5
  144. data/spec_app/app/assets/stylesheets/bootstrap_manifest.sass +0 -2
  145. data/spec_app/app/assets/stylesheets/integration_test.sass +0 -88
  146. data/spec_app/app/assets/stylesheets/jasmine_specs.sass +0 -20
  147. data/spec_app/app/controllers/application_controller.rb +0 -14
  148. data/spec_app/app/controllers/binding_test_controller.rb +0 -51
  149. data/spec_app/app/controllers/compiler_test_controller.rb +0 -5
  150. data/spec_app/app/controllers/css_test_controller.rb +0 -5
  151. data/spec_app/app/controllers/error_test_controller.rb +0 -5
  152. data/spec_app/app/controllers/form_test/basics_controller.rb +0 -14
  153. data/spec_app/app/controllers/form_test/redirects_controller.rb +0 -17
  154. data/spec_app/app/controllers/form_test/uploads_controller.rb +0 -15
  155. data/spec_app/app/controllers/hash_test_controller.rb +0 -5
  156. data/spec_app/app/controllers/method_test_controller.rb +0 -16
  157. data/spec_app/app/controllers/motion_test_controller.rb +0 -5
  158. data/spec_app/app/controllers/pages_controller.rb +0 -9
  159. data/spec_app/app/controllers/replace_test_controller.rb +0 -5
  160. data/spec_app/app/controllers/reveal_test_controller.rb +0 -5
  161. data/spec_app/app/controllers/scroll_test_controller.rb +0 -5
  162. data/spec_app/app/helpers/application_helper.rb +0 -2
  163. data/spec_app/app/mailers/.keep +0 -0
  164. data/spec_app/app/models/concerns/.keep +0 -0
  165. data/spec_app/app/views/compiler_test/timestamp.erb +0 -9
  166. data/spec_app/app/views/css_test/modal.erb +0 -47
  167. data/spec_app/app/views/css_test/modal_contents.erb +0 -5
  168. data/spec_app/app/views/css_test/modal_contents_wide.erb +0 -5
  169. data/spec_app/app/views/css_test/popup.erb +0 -81
  170. data/spec_app/app/views/css_test/popup_contents.erb +0 -5
  171. data/spec_app/app/views/css_test/tooltip.erb +0 -48
  172. data/spec_app/app/views/error_test/trigger.erb +0 -80
  173. data/spec_app/app/views/error_test/unexpected_response.erb +0 -3
  174. data/spec_app/app/views/form_test/basics/new.erb +0 -60
  175. data/spec_app/app/views/form_test/redirects/new.erb +0 -27
  176. data/spec_app/app/views/form_test/redirects/target.erb +0 -4
  177. data/spec_app/app/views/form_test/submission_result.erb +0 -30
  178. data/spec_app/app/views/form_test/uploads/new.erb +0 -44
  179. data/spec_app/app/views/hash_test/unpoly.erb +0 -30
  180. data/spec_app/app/views/hash_test/vanilla.erb +0 -13
  181. data/spec_app/app/views/layouts/integration_test.erb +0 -22
  182. data/spec_app/app/views/layouts/jasmine_rails/spec_runner.html.erb +0 -20
  183. data/spec_app/app/views/method_test/form_target.erb +0 -17
  184. data/spec_app/app/views/method_test/page1.erb +0 -11
  185. data/spec_app/app/views/method_test/page2.erb +0 -6
  186. data/spec_app/app/views/motion_test/animations.erb +0 -16
  187. data/spec_app/app/views/motion_test/transitions.erb +0 -13
  188. data/spec_app/app/views/pages/start.erb +0 -79
  189. data/spec_app/app/views/replace_test/_nav.erb +0 -6
  190. data/spec_app/app/views/replace_test/page1.erb +0 -14
  191. data/spec_app/app/views/replace_test/page2.erb +0 -14
  192. data/spec_app/app/views/replace_test/table.erb +0 -16
  193. data/spec_app/app/views/reveal_test/long1.erb +0 -17
  194. data/spec_app/app/views/reveal_test/long2.erb +0 -17
  195. data/spec_app/app/views/reveal_test/within_document_viewport.erb +0 -24
  196. data/spec_app/app/views/reveal_test/within_overflowing_div_viewport.erb +0 -28
  197. data/spec_app/app/views/scroll_test/long1.erb +0 -30
  198. data/spec_app/bin/bundle +0 -3
  199. data/spec_app/bin/rails +0 -8
  200. data/spec_app/bin/rake +0 -8
  201. data/spec_app/bin/setup +0 -29
  202. data/spec_app/bin/spring +0 -18
  203. data/spec_app/config.ru +0 -4
  204. data/spec_app/config/application.rb +0 -28
  205. data/spec_app/config/boot.rb +0 -3
  206. data/spec_app/config/database.yml +0 -25
  207. data/spec_app/config/environment.rb +0 -5
  208. data/spec_app/config/environments/development.rb +0 -41
  209. data/spec_app/config/environments/production.rb +0 -79
  210. data/spec_app/config/environments/test.rb +0 -42
  211. data/spec_app/config/initializers/assets.rb +0 -19
  212. data/spec_app/config/initializers/backtrace_silencers.rb +0 -7
  213. data/spec_app/config/initializers/bower_rails.rb +0 -16
  214. data/spec_app/config/initializers/cookies_serializer.rb +0 -3
  215. data/spec_app/config/initializers/filter_parameter_logging.rb +0 -4
  216. data/spec_app/config/initializers/inflections.rb +0 -16
  217. data/spec_app/config/initializers/mime_types.rb +0 -4
  218. data/spec_app/config/initializers/session_store.rb +0 -3
  219. data/spec_app/config/initializers/wrap_parameters.rb +0 -14
  220. data/spec_app/config/locales/en.yml +0 -23
  221. data/spec_app/config/routes.rb +0 -30
  222. data/spec_app/config/secrets.yml +0 -22
  223. data/spec_app/db/schema.rb +0 -23
  224. data/spec_app/db/seeds.rb +0 -7
  225. data/spec_app/lib/assets/.keep +0 -0
  226. data/spec_app/lib/tasks/.keep +0 -0
  227. data/spec_app/lib/tasks/cucumber.rake +0 -65
  228. data/spec_app/log/.keep +0 -0
  229. data/spec_app/public/404.html +0 -67
  230. data/spec_app/public/422.html +0 -67
  231. data/spec_app/public/500.html +0 -66
  232. data/spec_app/public/favicon.ico +0 -0
  233. data/spec_app/public/robots.txt +0 -5
  234. data/spec_app/script/cucumber +0 -10
  235. data/spec_app/spec/controllers/binding_test_controller_spec.rb +0 -248
  236. data/spec_app/spec/javascripts/helpers/agent_detector.coffee +0 -20
  237. data/spec_app/spec/javascripts/helpers/async_sequence.js.coffee +0 -103
  238. data/spec_app/spec/javascripts/helpers/browser_switches.js.coffee +0 -21
  239. data/spec_app/spec/javascripts/helpers/enable_logging.js.coffee +0 -2
  240. data/spec_app/spec/javascripts/helpers/fixture.js.coffee +0 -25
  241. data/spec_app/spec/javascripts/helpers/index.js.coffee +0 -1
  242. data/spec_app/spec/javascripts/helpers/jquery_no_conflict.js +0 -1
  243. data/spec_app/spec/javascripts/helpers/knife.js.coffee +0 -69
  244. data/spec_app/spec/javascripts/helpers/last_request.js.coffee +0 -25
  245. data/spec_app/spec/javascripts/helpers/mock_ajax.js.coffee +0 -8
  246. data/spec_app/spec/javascripts/helpers/mock_clock.js.coffee +0 -2
  247. data/spec_app/spec/javascripts/helpers/parse_form_data.js.coffee +0 -24
  248. data/spec_app/spec/javascripts/helpers/promise_state.js +0 -18
  249. data/spec_app/spec/javascripts/helpers/protect_jasmine_runner.coffee +0 -12
  250. data/spec_app/spec/javascripts/helpers/remove_body_margin.js.coffee +0 -8
  251. data/spec_app/spec/javascripts/helpers/reset_history.js.coffee +0 -23
  252. data/spec_app/spec/javascripts/helpers/reset_knife.js.coffee +0 -2
  253. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +0 -25
  254. data/spec_app/spec/javascripts/helpers/restore_body_scroll.js.coffee +0 -5
  255. data/spec_app/spec/javascripts/helpers/show_lib_versions.coffee +0 -12
  256. data/spec_app/spec/javascripts/helpers/spec_util.coffee +0 -47
  257. data/spec_app/spec/javascripts/helpers/to_be_around.js.coffee +0 -8
  258. data/spec_app/spec/javascripts/helpers/to_be_array.coffee +0 -5
  259. data/spec_app/spec/javascripts/helpers/to_be_attached.coffee +0 -9
  260. data/spec_app/spec/javascripts/helpers/to_be_blank.js.coffee +0 -8
  261. data/spec_app/spec/javascripts/helpers/to_be_detached.coffee +0 -9
  262. data/spec_app/spec/javascripts/helpers/to_be_element.js.coffee +0 -8
  263. data/spec_app/spec/javascripts/helpers/to_be_error.coffee +0 -8
  264. data/spec_app/spec/javascripts/helpers/to_be_given.js.coffee +0 -8
  265. data/spec_app/spec/javascripts/helpers/to_be_hidden.js.coffee +0 -8
  266. data/spec_app/spec/javascripts/helpers/to_be_jquery.js.coffee +0 -5
  267. data/spec_app/spec/javascripts/helpers/to_be_missing.js.coffee +0 -8
  268. data/spec_app/spec/javascripts/helpers/to_be_present.js.coffee +0 -8
  269. data/spec_app/spec/javascripts/helpers/to_be_scrolled_to.coffee +0 -11
  270. data/spec_app/spec/javascripts/helpers/to_be_visible.js.coffee +0 -9
  271. data/spec_app/spec/javascripts/helpers/to_contain.js.coffee +0 -8
  272. data/spec_app/spec/javascripts/helpers/to_end_with.js.coffee +0 -11
  273. data/spec_app/spec/javascripts/helpers/to_equal_jquery.js.coffee +0 -8
  274. data/spec_app/spec/javascripts/helpers/to_equal_node_list.coffee +0 -7
  275. data/spec_app/spec/javascripts/helpers/to_equal_via_is_equal.js.coffee +0 -7
  276. data/spec_app/spec/javascripts/helpers/to_have_class.js.coffee +0 -10
  277. data/spec_app/spec/javascripts/helpers/to_have_descendant.js.coffee +0 -10
  278. data/spec_app/spec/javascripts/helpers/to_have_length.js.coffee +0 -8
  279. data/spec_app/spec/javascripts/helpers/to_have_opacity.coffee +0 -15
  280. data/spec_app/spec/javascripts/helpers/to_have_own_property.js.coffee +0 -8
  281. data/spec_app/spec/javascripts/helpers/to_have_request_method.js.coffee +0 -16
  282. data/spec_app/spec/javascripts/helpers/to_have_text.js.coffee +0 -9
  283. data/spec_app/spec/javascripts/helpers/to_have_unhandled_rejections.coffee +0 -18
  284. data/spec_app/spec/javascripts/helpers/to_match_list.coffee +0 -14
  285. data/spec_app/spec/javascripts/helpers/to_match_selector.coffee +0 -8
  286. data/spec_app/spec/javascripts/helpers/to_match_text.js.coffee +0 -13
  287. data/spec_app/spec/javascripts/helpers/to_match_url.coffee +0 -14
  288. data/spec_app/spec/javascripts/helpers/trigger.js.coffee +0 -200
  289. data/spec_app/spec/javascripts/helpers/wait_until_dom_ready.js.coffee +0 -5
  290. data/spec_app/spec/javascripts/support/jasmine.yml +0 -51
  291. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +0 -150
  292. data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +0 -82
  293. data/spec_app/spec/javascripts/up/classes/config_spec.coffee +0 -24
  294. data/spec_app/spec/javascripts/up/classes/divertible_chain_spec.coffee +0 -45
  295. data/spec_app/spec/javascripts/up/classes/focus_tracker_spec.coffee +0 -34
  296. data/spec_app/spec/javascripts/up/classes/params_spec.coffee +0 -557
  297. data/spec_app/spec/javascripts/up/classes/request_spec.coffee +0 -50
  298. data/spec_app/spec/javascripts/up/classes/scroll_motion_spec.js.coffee +0 -51
  299. data/spec_app/spec/javascripts/up/classes/store/memory_spec.js.coffee +0 -70
  300. data/spec_app/spec/javascripts/up/classes/store/session_spec.js.coffee +0 -114
  301. data/spec_app/spec/javascripts/up/element_spec.coffee +0 -897
  302. data/spec_app/spec/javascripts/up/event_spec.js.coffee +0 -530
  303. data/spec_app/spec/javascripts/up/feedback_spec.js.coffee +0 -401
  304. data/spec_app/spec/javascripts/up/form_spec.js.coffee +0 -1488
  305. data/spec_app/spec/javascripts/up/fragment_spec.js.coffee +0 -2589
  306. data/spec_app/spec/javascripts/up/history_spec.js.coffee +0 -340
  307. data/spec_app/spec/javascripts/up/jquery_spec.js.coffee +0 -4
  308. data/spec_app/spec/javascripts/up/legacy_spec.js.coffee +0 -27
  309. data/spec_app/spec/javascripts/up/link_spec.js.coffee +0 -1093
  310. data/spec_app/spec/javascripts/up/log_spec.js.coffee +0 -119
  311. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +0 -917
  312. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +0 -582
  313. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +0 -507
  314. data/spec_app/spec/javascripts/up/protocol_spec.js.coffee +0 -39
  315. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +0 -1137
  316. data/spec_app/spec/javascripts/up/radio_spec.js.coffee +0 -212
  317. data/spec_app/spec/javascripts/up/rails_spec.js.coffee +0 -118
  318. data/spec_app/spec/javascripts/up/spec_spec.js.coffee +0 -9
  319. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +0 -304
  320. data/spec_app/spec/javascripts/up/toast_spec.js.coffee +0 -37
  321. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +0 -163
  322. data/spec_app/spec/javascripts/up/util_spec.js.coffee +0 -1420
  323. data/spec_app/spec/javascripts/up/viewport_spec.js.coffee +0 -655
  324. data/spec_app/spec/spec_helper.rb +0 -62
  325. data/spec_app/test/controllers/.keep +0 -0
  326. data/spec_app/test/fixtures/.keep +0 -0
  327. data/spec_app/test/helpers/.keep +0 -0
  328. data/spec_app/test/integration/.keep +0 -0
  329. data/spec_app/test/mailers/.keep +0 -0
  330. data/spec_app/test/models/.keep +0 -0
  331. data/spec_app/test/test_helper.rb +0 -10
  332. data/spec_app/vendor/asset-libs/es6-promise-4.1.6/es6-promise.auto.js +0 -1159
  333. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.bower.json +0 -43
  334. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.gitignore +0 -6
  335. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.npmignore +0 -10
  336. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.pairs +0 -6
  337. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.travis.yml +0 -56
  338. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/jasmine-ajax.js +0 -790
  339. data/spec_app/vendor/assets/.keep +0 -0
  340. data/unpoly-rails.gemspec +0 -24
@@ -1,298 +0,0 @@
1
- ###**
2
- Server protocol
3
- ===============
4
-
5
- You rarely need to change server-side code
6
- in order to use Unpoly. There is no need to provide a JSON API, or add
7
- extra routes for AJAX requests. The server simply renders a series
8
- of full HTML pages, just like it would without Unpoly.
9
-
10
- That said, there is an **optional** protocol your server can use to
11
- exchange additional information when Unpoly is [updating fragments](/up.link).
12
-
13
- While the protocol can help you optimize performance and handle some
14
- edge cases, implementing it is **entirely optional**. For instance,
15
- `unpoly.com` itself is a static site that uses Unpoly on the frontend
16
- and doesn't even have a server component.
17
-
18
- ## Existing implementations
19
-
20
- You should be able to implement the protocol in a very short time.
21
- There are existing implementations for various web frameworks:
22
-
23
- - [Ruby on Rails](/install/rails)
24
- - [Roda](https://github.com/adam12/roda-unpoly)
25
- - [Rack](https://github.com/adam12/rack-unpoly) (Sinatra, Padrino, Hanami, Cuba, ...)
26
- - [Phoenix](https://elixirforum.com/t/unpoly-a-framework-like-turbolinks/3614/15) (Elixir)
27
-
28
-
29
- ## Protocol details
30
-
31
- \#\#\# Redirect detection for IE11
32
-
33
- On Internet Explorer 11, Unpoly cannot detect the final URL after a redirect.
34
- You can fix this edge case by delivering an additional HTTP header
35
- with the *last* response in a series of redirects:
36
-
37
- ```http
38
- X-Up-Location: /current-url
39
- ```
40
-
41
- The **simplest implementation** is to set these headers for every request.
42
-
43
-
44
- \#\#\# Optimizing responses
45
-
46
- When [updating a fragment](/up.link), Unpoly will send an
47
- additional HTTP header containing the CSS selector that is being replaced:
48
-
49
- ```http
50
- X-Up-Target: .user-list
51
- ```
52
-
53
- Server-side code is free to **optimize its response** by only returning HTML
54
- that matches the selector. For example, you might prefer to not render an
55
- expensive sidebar if the sidebar is not targeted.
56
-
57
- Unpoly will often update a different selector in case the request fails.
58
- This selector is also included as a HTTP header:
59
-
60
- ```
61
- X-Up-Fail-Target: body
62
- ```
63
-
64
-
65
- \#\#\# Pushing a document title to the client
66
-
67
- When [updating a fragment](/up.link), Unpoly will by default
68
- extract the `<title>` from the server response and update the document title accordingly.
69
-
70
- The server can also force Unpoly to set a document title by passing a HTTP header:
71
-
72
- ```http
73
- X-Up-Title: My server-pushed title
74
- ```
75
-
76
- This is useful when you [optimize your response](#optimizing-responses) and not render
77
- the application layout unless it is targeted. Since your optimized response
78
- no longer includes a `<title>`, you can instead use the HTTP header to pass the document title.
79
-
80
-
81
- \#\#\# Signaling failed form submissions
82
-
83
- When [submitting a form via AJAX](/form-up-target)
84
- Unpoly needs to know whether the form submission has failed (to update the form with
85
- validation errors) or succeeded (to update the `up-target` selector).
86
-
87
- For Unpoly to be able to detect a failed form submission, the response must be
88
- return a non-200 HTTP status code. We recommend to use either
89
- 400 (bad request) or 422 (unprocessable entity).
90
-
91
- To do so in [Ruby on Rails](http://rubyonrails.org/), pass a [`:status` option to `render`](http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option):
92
-
93
- class UsersController < ApplicationController
94
-
95
- def create
96
- user_params = params[:user].permit(:email, :password)
97
- @user = User.new(user_params)
98
- if @user.save?
99
- sign_in @user
100
- else
101
- render 'form', status: :bad_request
102
- end
103
- end
104
-
105
- end
106
-
107
-
108
- \#\#\# Detecting live form validations
109
-
110
- When [validating a form](/input-up-validate), Unpoly will
111
- send an additional HTTP header containing a CSS selector for the form that is
112
- being updated:
113
-
114
- ```http
115
- X-Up-Validate: .user-form
116
- ```
117
-
118
- When detecting a validation request, the server is expected to **validate (but not save)**
119
- the form submission and render a new copy of the form with validation errors.
120
-
121
- Below you will an example for a writing route that is aware of Unpoly's live form
122
- validations. The code is for [Ruby on Rails](http://rubyonrails.org/),
123
- but you can adapt it for other languages:
124
-
125
- class UsersController < ApplicationController
126
-
127
- def create
128
- user_params = params[:user].permit(:email, :password)
129
- @user = User.new(user_params)
130
- if request.headers['X-Up-Validate']
131
- @user.valid? # run validations, but don't save to the database
132
- render 'form' # render form with error messages
133
- elsif @user.save?
134
- sign_in @user
135
- else
136
- render 'form', status: :bad_request
137
- end
138
- end
139
-
140
- end
141
-
142
-
143
- \#\#\# Signaling the initial request method
144
-
145
- If the initial page was loaded with a non-`GET` HTTP method, Unpoly prefers to make a full
146
- page load when you try to update a fragment. Once the next page was loaded with a `GET` method,
147
- Unpoly will restore its standard behavior.
148
-
149
- This fixes two edge cases you might or might not care about:
150
-
151
- 1. Unpoly replaces the initial page state so it can later restore it when the user
152
- goes back to that initial URL. However, if the initial request was a POST,
153
- Unpoly will wrongly assume that it can restore the state by reloading with GET.
154
- 2. Some browsers have a bug where the initial request method is used for all
155
- subsequently pushed states. That means if the user reloads the page on a later
156
- GET state, the browser will wrongly attempt a POST request.
157
- This issue affects Safari 9-12 (last tested in 2019-03).
158
- Modern Firefoxes, Chromes and IE10+ don't have this behavior.
159
-
160
- In order to allow Unpoly to detect the HTTP method of the initial page load,
161
- the server must set a cookie:
162
-
163
- ```http
164
- Set-Cookie: _up_method=POST
165
- ```
166
-
167
- When Unpoly boots, it will look for this cookie and configure its behavior accordingly.
168
- The cookie is then deleted in order to not affect following requests.
169
-
170
- The **simplest implementation** is to set this cookie for every request that is neither
171
- `GET` nor contains an [`X-Up-Target` header](/#optimizing-responses). For all other requests
172
- an existing cookie should be deleted.
173
-
174
-
175
- @module up.protocol
176
- ###
177
- up.protocol = do ->
178
-
179
- u = up.util
180
- e = up.element
181
-
182
- ###**
183
- @function up.protocol.locationFromXhr
184
- @internal
185
- ###
186
- locationFromXhr = (xhr) ->
187
- xhr.getResponseHeader(config.locationHeader) || xhr.responseURL
188
-
189
- ###**
190
- @function up.protocol.titleFromXhr
191
- @internal
192
- ###
193
- titleFromXhr = (xhr) ->
194
- xhr.getResponseHeader(config.titleHeader)
195
-
196
- ###**
197
- @function up.protocol.methodFromXhr
198
- @internal
199
- ###
200
- methodFromXhr = (xhr) ->
201
- if method = xhr.getResponseHeader(config.methodHeader)
202
- u.normalizeMethod(method)
203
-
204
- ###**
205
- Server-side companion libraries like unpoly-rails set this cookie so we
206
- have a way to detect the request method of the initial page load.
207
- There is no JavaScript API for this.
208
-
209
- @function up.protocol.initialRequestMethod
210
- @internal
211
- ###
212
- initialRequestMethod = u.memoize ->
213
- methodFromServer = up.browser.popCookie(config.methodCookie)
214
- (methodFromServer || 'get').toLowerCase()
215
-
216
- # Remove the method cookie as soon as possible.
217
- # Don't wait until the first call to initialRequestMethod(),
218
- # which might be much later.
219
- up.on('up:framework:booted', initialRequestMethod)
220
-
221
- ###**
222
- Configures strings used in the optional [server protocol](/up.protocol).
223
-
224
- @property up.protocol.config
225
- @param {String} [config.targetHeader='X-Up-Target']
226
- @param {String} [config.failTargetHeader='X-Up-Fail-Target']
227
- @param {String} [config.locationHeader='X-Up-Location']
228
- @param {String} [config.titleHeader='X-Up-Title']
229
- @param {String} [config.validateHeader='X-Up-Validate']
230
- @param {String} [config.methodHeader='X-Up-Method']
231
- @param {String} [config.methodCookie='_up_method']
232
- The name of the optional cookie the server can send to
233
- [signal the initial request method](/up.protocol#signaling-the-initial-request-method).
234
- @param {String} [config.methodParam='_method']
235
- The name of the POST parameter when [wrapping HTTP methods](/up.proxy.config#config.wrapMethods)
236
- in a `POST` request.
237
- @param {String} [config.csrfHeader='X-CSRF-Token']
238
- The name of the HTTP header that will include the
239
- [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern)
240
- for AJAX requests.
241
- @param {string|Function(): string} [config.csrfParam]
242
- The `name` of the hidden `<input>` used for sending a
243
- [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern) when
244
- submitting a default, non-AJAX form. For AJAX request the token is sent as an HTTP header instead.
245
-
246
- The parameter name can be configured as a string or as function that returns the parameter name.
247
- If no name is set, no token will be sent.
248
-
249
- Defaults to the `content` attribute of a `<meta>` tag named `csrf-param`:
250
-
251
- <meta name="csrf-param" content="authenticity_token" />
252
-
253
- @param {string|Function(): string} [config.csrfToken]
254
- The [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern)
255
- to send for unsafe requests. The token will be sent as either a HTTP header (for AJAX requests)
256
- or hidden form `<input>` (for default, non-AJAX form submissions).
257
-
258
- The token can either be configured as a string or as function that returns the token.
259
- If no token is set, no token will be sent.
260
-
261
- Defaults to the `content` attribute of a `<meta>` tag named `csrf-token`:
262
-
263
- <meta name='csrf-token' content='secret12345'>
264
-
265
- @experimental
266
- ###
267
- config = new up.Config
268
- targetHeader: 'X-Up-Target'
269
- failTargetHeader: 'X-Up-Fail-Target'
270
- locationHeader: 'X-Up-Location'
271
- validateHeader: 'X-Up-Validate'
272
- titleHeader: 'X-Up-Title'
273
- methodHeader: 'X-Up-Method'
274
- methodCookie: '_up_method'
275
- methodParam: '_method'
276
- csrfParam: -> e.metaContent('csrf-param')
277
- csrfToken: -> e.metaContent('csrf-token')
278
- csrfHeader: 'X-CSRF-Token'
279
-
280
- csrfParam = ->
281
- u.evalOption(config.csrfParam)
282
-
283
- csrfToken = ->
284
- u.evalOption(config.csrfToken)
285
-
286
- reset = ->
287
- config.reset()
288
-
289
- up.on 'up:framework:reset', reset
290
-
291
- config: config
292
- reset: reset
293
- locationFromXhr: locationFromXhr
294
- titleFromXhr: titleFromXhr
295
- methodFromXhr: methodFromXhr
296
- csrfParam :csrfParam
297
- csrfToken: csrfToken
298
- initialRequestMethod: initialRequestMethod
@@ -1,672 +0,0 @@
1
- ###**
2
- AJAX acceleration
3
- =================
4
-
5
- Unpoly comes with a number of tricks to shorten the latency between browser and server.
6
-
7
- \#\#\# Server responses are cached by default
8
-
9
- Unpoly caches server responses for a few minutes,
10
- making requests to these URLs return instantly.
11
- All Unpoly functions and selectors go through this cache, unless
12
- you explicitly pass a `{ cache: false }` option or set an `up-cache="false"` attribute.
13
-
14
- The cache holds up to 70 responses for 5 minutes. You can configure the cache size and expiry using
15
- [`up.proxy.config`](/up.proxy.config), or clear the cache manually using [`up.proxy.clear()`](/up.proxy.clear).
16
-
17
- Also the entire cache is cleared with every non-`GET` request (like `POST` or `PUT`).
18
-
19
- If you need to make cache-aware requests from your [custom JavaScript](/up.syntax),
20
- use [`up.request()`](/up.request).
21
-
22
- \#\#\# Preloading links
23
-
24
- Unpoly also lets you speed up reaction times by [preloading
25
- links](/a-up-preload) when the user hovers over the click area (or puts the mouse/finger
26
- down). This way the response will already be cached when
27
- the user releases the mouse/finger.
28
-
29
- \#\#\# Spinners
30
-
31
- You can listen to the [`up:proxy:slow`](/up:proxy:slow) event to implement a spinner
32
- that appears during a long-running request.
33
-
34
- \#\#\# More acceleration
35
-
36
- Other Unpoly modules contain even more tricks to outsmart network latency:
37
-
38
- - [Instantaneous feedback for links that are currently loading](/a.up-active)
39
- - [Follow links on `mousedown` instead of `click`](/a-up-instant)
40
-
41
- @module up.proxy
42
- ###
43
- up.proxy = do ->
44
-
45
- u = up.util
46
- e = up.element
47
-
48
- waitingLink = undefined
49
- preloadDelayTimer = undefined
50
- slowDelayTimer = undefined
51
- pendingCount = undefined
52
- slowEventEmitted = undefined
53
-
54
- queuedLoaders = []
55
-
56
- ###**
57
- @property up.proxy.config
58
- @param {number} [config.preloadDelay=75]
59
- The number of milliseconds to wait before [`[up-preload]`](/a-up-preload)
60
- starts preloading.
61
- @param {number} [config.cacheSize=70]
62
- The maximum number of responses to cache.
63
- If the size is exceeded, the oldest items will be dropped from the cache.
64
- @param {number} [config.cacheExpiry=300000]
65
- The number of milliseconds until a cache entry expires.
66
- Defaults to 5 minutes.
67
- @param {number} [config.slowDelay=300]
68
- How long the proxy waits until emitting the [`up:proxy:slow` event](/up:proxy:slow).
69
- Use this to prevent flickering of spinners.
70
- @param {number} [config.maxRequests=4]
71
- The maximum number of concurrent requests to allow before additional
72
- requests are queued. This currently ignores preloading requests.
73
-
74
- You might find it useful to set this to `1` in full-stack integration
75
- tests (e.g. Selenium).
76
-
77
- Note that your browser might [impose its own request limit](http://www.browserscope.org/?category=network)
78
- regardless of what you configure here.
79
- @param {Array<string>} [config.wrapMethods]
80
- An array of uppercase HTTP method names. AJAX requests with one of these methods
81
- will be converted into a `POST` request and carry their original method as a `_method`
82
- parameter. This is to [prevent unexpected redirect behavior](https://makandracards.com/makandra/38347).
83
- @param {Array<string>} [config.safeMethods]
84
- An array of uppercase HTTP method names that are considered [safe](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1).
85
- The proxy cache will only cache safe requests and will clear the entire
86
- cache after an unsafe request.
87
- @stable
88
- ###
89
- config = new up.Config
90
- slowDelay: 300
91
- preloadDelay: 75
92
- cacheSize: 70
93
- cacheExpiry: 1000 * 60 * 5
94
- maxRequests: 4
95
- wrapMethods: ['PATCH', 'PUT', 'DELETE']
96
- safeMethods: ['GET', 'OPTIONS', 'HEAD']
97
-
98
- cache = new up.Cache
99
- size: -> config.cacheSize
100
- expiry: -> config.cacheExpiry
101
- key: (request) -> up.Request.wrap(request).cacheKey()
102
- cachable: (request) -> up.Request.wrap(request).isCachable()
103
- # logPrefix: 'up.proxy'
104
-
105
- ###**
106
- Returns a cached response for the given request.
107
-
108
- Returns `undefined` if the given request is not currently cached.
109
-
110
- @function up.proxy.get
111
- @return {Promise<up.Response>}
112
- A promise for the response.
113
- @experimental
114
- ###
115
- get = (request) ->
116
- request = up.Request.wrap(request)
117
- candidates = [request]
118
-
119
- if request.target != 'html'
120
- # Since <html> is the root tag, a request for the `html` selector
121
- # will contain all other selectors.
122
- requestForHtml = request.variant(target: 'html')
123
- candidates.push(requestForHtml)
124
-
125
- # Although <body> is not the root tag, we consider it the selector developers
126
- # will use when they want to replace the entire page. Hence we consider it
127
- # a suitable match for all other selectors, including `html`.
128
- if request.target != 'body'
129
- requestForBody = request.variant(target: 'body')
130
- candidates.push(requestForBody)
131
-
132
- for candidate in candidates
133
- if response = cache.get(candidate)
134
- return response
135
-
136
- cancelPreloadDelay = ->
137
- clearTimeout(preloadDelayTimer)
138
- preloadDelayTimer = null
139
-
140
- cancelSlowDelay = ->
141
- clearTimeout(slowDelayTimer)
142
- slowDelayTimer = null
143
-
144
- reset = ->
145
- waitingLink = null
146
- cancelPreloadDelay()
147
- cancelSlowDelay()
148
- pendingCount = 0
149
- config.reset()
150
- cache.clear()
151
- slowEventEmitted = false
152
- queuedLoaders = []
153
-
154
- reset()
155
-
156
- ###**
157
- Makes an AJAX request to the given URL.
158
-
159
- \#\#\# Example
160
-
161
- up.request('/search', { params: { query: 'sunshine' } }).then(function(response) {
162
- console.log('The response text is %o', response.text)
163
- }).catch(function() {
164
- console.error('The request failed')
165
- })
166
-
167
- \#\#\# Caching
168
-
169
- All responses are cached by default. If requesting a URL with a non-`GET` method, the response will
170
- not be cached and the entire cache will be cleared.
171
-
172
- You can configure caching with the [`up.proxy.config`](/up.proxy.config) property.
173
-
174
- \#\#\# Events
175
-
176
- If a network connection is attempted, the proxy will emit
177
- a [`up:proxy:load`](/up:proxy:load) event with the `request` as its argument.
178
- Once the response is received, a [`up:proxy:loaded`](/up:proxy:loaded) event will
179
- be emitted.
180
-
181
- @function up.request
182
- @param {string} [url]
183
- The URL for the request.
184
-
185
- Instead of passing the URL as a string argument, you can also pass it as an `{ url }` option.
186
- @param {string} [options.url]
187
- You can omit the first string argument and pass the URL as
188
- a `request` property instead.
189
- @param {string} [options.method='GET']
190
- The HTTP method for the options.
191
- @param {boolean} [options.cache]
192
- Whether to use a cached response for [safe](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1)
193
- requests, if available. If set to `false` a network connection will always be attempted.
194
- @param {Object} [options.headers={}]
195
- An object of additional HTTP headers.
196
- @param {Object|FormData|string|Array} [options.params={}]
197
- [Parameters](/up.Params) that should be sent as the request's payload.
198
- @param {string} [options.timeout]
199
- A timeout in milliseconds.
200
-
201
- If [`up.proxy.config.maxRequests`](/up.proxy.config#config.maxRequests) is set, the timeout
202
- will not include the time spent waiting in the queue.
203
- @param {string} [options.target='body']
204
- The CSS selector that will be sent as an [`X-Up-Target` header](/up.protocol#optimizing-responses).
205
- @param {string} [options.failTarget='body']
206
- The CSS selector that will be sent as an [`X-Up-Fail-Target` header](/up.protocol#optimizing-responses).
207
- @return {Promise<up.Response>}
208
- A promise for the response.
209
- @stable
210
- ###
211
- makeRequest = (args...) ->
212
- if u.isString(args[0])
213
- url = args.shift()
214
-
215
- # We cannot use u.extractOptions() since sometimes the last argument
216
- # is an up.Request instead of a basic object.
217
- requestOrOptions = args.shift() || {}
218
-
219
- if url
220
- requestOrOptions.url = url
221
-
222
- request = up.Request.wrap(requestOrOptions)
223
-
224
- # Non-GET requests always touch the network
225
- # unless `request.cache` is explicitly set to `true`.
226
- # These requests are never cached.
227
- if !request.isSafe()
228
- # We clear the entire cache before an unsafe request, since we
229
- # assume the user is writing a change.
230
- clear()
231
-
232
- ignoreCache = (request.cache == false)
233
-
234
- # If we have an existing promise matching this new request,
235
- # we use it unless `request.cache` is explicitly set to `false`.
236
- if !ignoreCache && (promise = get(request))
237
- up.puts 'Re-using cached response for %s %s', request.method, request.url
238
- else
239
- # If no existing promise is available, we make a network request.
240
- promise = loadOrQueue(request)
241
- set(request, promise)
242
- # Uncache failed requests
243
- promise.catch ->
244
- remove(request)
245
-
246
- if !request.preload
247
- # This might actually make `pendingCount` higher than the actual
248
- # number of outstanding requests. However, we need to cover the
249
- # following case:
250
- #
251
- # - User starts preloading a request.
252
- # This triggers *no* `up:proxy:slow`.
253
- # - User starts loading the request (without preloading).
254
- # This triggers `up:proxy:slow`.
255
- # - The request finishes.
256
- # This triggers `up:proxy:recover`.
257
- loadStarted()
258
- u.always promise, loadEnded
259
-
260
- promise
261
-
262
- ###**
263
- Makes an AJAX request to the given URL and caches the response.
264
-
265
- The function returns a promise that fulfills with the response text.
266
-
267
- \#\#\# Example
268
-
269
- up.request('/search', { params: { query: 'sunshine' } }).then(function(text) {
270
- console.log('The response text is %o', text)
271
- }).catch(function() {
272
- console.error('The request failed')
273
- })
274
-
275
- @function up.ajax
276
- @param {string} [url]
277
- The URL for the request.
278
-
279
- Instead of passing the URL as a string argument, you can also pass it as an `{ url }` option.
280
- @param {string} [request.url]
281
- You can omit the first string argument and pass the URL as
282
- a `request` property instead.
283
- @param {string} [request.method='GET']
284
- The HTTP method for the request.
285
- @param {boolean} [request.cache]
286
- Whether to use a cached response for [safe](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1)
287
- requests, if available. If set to `false` a network connection will always be attempted.
288
- @param {Object} [request.headers={}]
289
- An object of additional header key/value pairs to send along
290
- with the request.
291
- @param {Object|FormData|string|Array} [options.params]
292
- [Parameters](/up.Params) that should be sent as the request's payload.
293
-
294
- On IE 11 and Edge, `FormData` payloads require a [polyfill for `FormData#entries()`](https://github.com/jimmywarting/FormData).
295
- @param {string} [request.timeout]
296
- A timeout in milliseconds for the request.
297
-
298
- If [`up.proxy.config.maxRequests`](/up.proxy.config#config.maxRequests) is set, the timeout
299
- will not include the time spent waiting in the queue.
300
- @return {Promise<string>}
301
- A promise for the response text.
302
- @deprecated
303
- Use [`up.request()`](/up.request) instead.
304
- ###
305
- ajax = (args...) ->
306
- up.legacy.warn('up.ajax() has been deprecated. Use up.request() instead.')
307
- new Promise (resolve, reject) ->
308
- pickResponseText = (response) -> resolve(response.text)
309
- makeRequest(args...).then(pickResponseText, reject)
310
-
311
- ###**
312
- Returns `true` if the proxy is not currently waiting
313
- for a request to finish. Returns `false` otherwise.
314
-
315
- @function up.proxy.isIdle
316
- @return {boolean}
317
- Whether the proxy is idle
318
- @experimental
319
- ###
320
- isIdle = ->
321
- pendingCount == 0
322
-
323
- ###**
324
- Returns `true` if the proxy is currently waiting
325
- for a request to finish. Returns `false` otherwise.
326
-
327
- @function up.proxy.isBusy
328
- @return {boolean}
329
- Whether the proxy is busy
330
- @experimental
331
- ###
332
- isBusy = ->
333
- pendingCount > 0
334
-
335
- loadStarted = ->
336
- pendingCount += 1
337
- unless slowDelayTimer
338
- # Since the emission of up:proxy:slow might be delayed by config.slowDelay,
339
- # we wrap the mission in a function for scheduling below.
340
- emission = ->
341
- if isBusy() # a fast response might have beaten the delay
342
- up.emit('up:proxy:slow', log: 'Proxy is slow to respond')
343
- slowEventEmitted = true
344
- slowDelayTimer = u.timer(config.slowDelay, emission)
345
-
346
-
347
- ###**
348
- This event is [emitted](/up.emit) when [AJAX requests](/up.request)
349
- are taking long to finish.
350
-
351
- By default Unpoly will wait 300 ms for an AJAX request to finish
352
- before emitting `up:proxy:slow`. You can configure this time like this:
353
-
354
- up.proxy.config.slowDelay = 150;
355
-
356
- Once all responses have been received, an [`up:proxy:recover`](/up:proxy:recover)
357
- will be emitted.
358
-
359
- Note that if additional requests are made while Unpoly is already busy
360
- waiting, **no** additional `up:proxy:slow` events will be triggered.
361
-
362
-
363
- \#\#\# Spinners
364
-
365
- You can [listen](/up.on) to the `up:proxy:slow`
366
- and [`up:proxy:recover`](/up:proxy:recover) events to implement a spinner
367
- that appears during a long-running request,
368
- and disappears once the response has been received:
369
-
370
- <div class="spinner">Please wait!</div>
371
-
372
- Here is the JavaScript to make it alive:
373
-
374
- up.compiler('.spinner', function(element) {
375
- show = () => { up.element.show(element) }
376
- hide = () => { up.element.hide(element) }
377
-
378
- hide()
379
-
380
- return [
381
- up.on('up:proxy:slow', show),
382
- up.on('up:proxy:recover', hide)
383
- ]
384
- })
385
-
386
- The `up:proxy:slow` event will be emitted after a delay of 300 ms
387
- to prevent the spinner from flickering on and off.
388
- You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.config) like this:
389
-
390
- up.proxy.config.slowDelay = 150;
391
-
392
-
393
- @event up:proxy:slow
394
- @stable
395
- ###
396
-
397
- loadEnded = ->
398
- pendingCount -= 1
399
-
400
- if isIdle()
401
- cancelSlowDelay()
402
- if slowEventEmitted
403
- up.emit('up:proxy:recover', log: 'Proxy has recovered from slow response')
404
- slowEventEmitted = false
405
-
406
- ###**
407
- This event is [emitted](/up.emit) when [AJAX requests](/up.request)
408
- have [taken long to finish](/up:proxy:slow), but have finished now.
409
-
410
- See [`up:proxy:slow`](/up:proxy:slow) for more documentation on
411
- how to use this event for implementing a spinner that shows during
412
- long-running requests.
413
-
414
- @event up:proxy:recover
415
- @stable
416
- ###
417
- loadOrQueue = (request) ->
418
- if pendingCount < config.maxRequests
419
- load(request)
420
- else
421
- queue(request)
422
-
423
- queue = (request) ->
424
- up.puts('Queuing request for %s %s', request.method, request.url)
425
- loader = -> load(request)
426
- loader = u.previewable(loader)
427
- queuedLoaders.push(loader)
428
- loader.promise
429
-
430
- load = (request) ->
431
- eventProps =
432
- request: request
433
- log: ['Loading %s %s', request.method, request.url]
434
-
435
- if up.event.nobodyPrevents('up:proxy:load', eventProps)
436
- responsePromise = request.send()
437
- u.always responsePromise, responseReceived
438
- u.always responsePromise, pokeQueue
439
- responsePromise
440
- else
441
- u.microtask(pokeQueue)
442
- Promise.reject(new Error('Event up:proxy:load was prevented'))
443
-
444
- ###**
445
- This event is [emitted](/up.emit) before an [AJAX request](/up.request)
446
- is sent over the network.
447
-
448
- @event up:proxy:load
449
- @param {up.Request} event.request
450
- @param event.preventDefault()
451
- Event listeners may call this method to prevent the request from being sent.
452
- @experimental
453
- ###
454
-
455
- registerAliasForRedirect = (response) ->
456
- request = response.request
457
- if response.url && request.url != response.url
458
- newRequest = request.variant(
459
- method: response.method
460
- url: response.url
461
- )
462
- up.proxy.alias(request, newRequest)
463
-
464
- responseReceived = (response) ->
465
- if response.isFatalError()
466
- up.emit 'up:proxy:fatal',
467
- log: 'Fatal error during request'
468
- request: response.request
469
- response: response
470
- else
471
- registerAliasForRedirect(response) unless response.isError()
472
- up.emit 'up:proxy:loaded',
473
- log: ['Server responded with HTTP %d (%d bytes)', response.status, response.text.length]
474
- request: response.request
475
- response: response
476
-
477
- ###**
478
- This event is [emitted](/up.emit) when the response to an
479
- [AJAX request](/up.request) has been received.
480
-
481
- Note that this event will also be emitted when the server signals an
482
- error with an HTTP status like `500`. Only if the request
483
- encounters a fatal error (like a loss of network connectivity),
484
- [`up:proxy:fatal`](/up:proxy:fatal) is emitted instead.
485
-
486
- @event up:proxy:loaded
487
- @param {up.Request} event.request
488
- @param {up.Response} event.response
489
- @experimental
490
- ###
491
-
492
- ###**
493
- This event is [emitted](/up.emit) when an [AJAX request](/up.request)
494
- encounters fatal error like a timeout or loss of network connectivity.
495
-
496
- Note that this event will *not* be emitted when the server produces an
497
- error message with an HTTP status like `500`. When the server can produce
498
- any response, [`up:proxy:loaded`](/up:proxy:loaded) is emitted instead.
499
-
500
- @event up:proxy:fatal
501
- ###
502
-
503
- pokeQueue = ->
504
- queuedLoaders.shift()?()
505
- # Don't return the promise from the loader above
506
- return undefined
507
-
508
- ###**
509
- Makes the proxy assume that `newRequest` has the same response as the
510
- already cached `oldRequest`.
511
-
512
- Unpoly uses this internally when the user redirects from `/old` to `/new`.
513
- In that case, both `/old` and `/new` will cache the same response from `/new`.
514
-
515
- @function up.proxy.alias
516
- @param {Object} oldRequest
517
- @param {Object} newRequest
518
- @experimental
519
- ###
520
- alias = cache.alias
521
-
522
- ###**
523
- Manually stores a promise for the response to the given request.
524
-
525
- @function up.proxy.set
526
- @param {string} request.url
527
- @param {string} [request.method='GET']
528
- @param {string} [request.target='body']
529
- @param {Promise<up.Response>} response
530
- A promise for the response.
531
- @experimental
532
- ###
533
- set = cache.set
534
-
535
- ###**
536
- Manually removes the given request from the cache.
537
-
538
- You can also [configure](/up.proxy.config) when the proxy
539
- automatically removes cache entries.
540
-
541
- @function up.proxy.remove
542
- @param {string} request.url
543
- @param {string} [request.method='GET']
544
- @param {string} [request.target='body']
545
- @experimental
546
- ###
547
- remove = cache.remove
548
-
549
- ###**
550
- Removes all cache entries.
551
-
552
- Unpoly also automatically clears the cache whenever it processes
553
- a request with an [unsafe](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1)
554
- HTTP method like `POST`.
555
-
556
- @function up.proxy.clear
557
- @stable
558
- ###
559
- clear = cache.clear
560
-
561
- # up.legacy.renamedEvent('up:proxy:received', 'up:proxy:loaded')
562
-
563
- preloadAfterDelay = (link) ->
564
- delay = e.numberAttr(link, 'up-delay') || config.preloadDelay
565
- unless link == waitingLink
566
- waitingLink = link
567
- cancelPreloadDelay()
568
- curriedPreload = ->
569
- u.muteRejection preload(link)
570
- waitingLink = null
571
- startPreloadDelay(curriedPreload, delay)
572
-
573
- startPreloadDelay = (block, delay) ->
574
- preloadDelayTimer = setTimeout(block, delay)
575
-
576
- stopPreload = (link) ->
577
- if link == waitingLink
578
- waitingLink = undefined
579
- cancelPreloadDelay()
580
-
581
- ###**
582
- Preloads the given link.
583
-
584
- When the link is clicked later, the response will already be cached,
585
- making the interaction feel instant.
586
-
587
- @function up.proxy.preload
588
- @param {string|Element|jQuery} linkOrSelector
589
- The element whose destination should be preloaded.
590
- @param {Object} options
591
- Options that will be passed to the function making the HTTP requests.
592
- @return
593
- A promise that will be fulfilled when the request was loaded and cached
594
- @experimental
595
- ###
596
- preload = (linkOrSelector, options) ->
597
- link = e.get(linkOrSelector)
598
-
599
- if up.link.isSafe(link)
600
- preloadEventAttrs = { log: ['Preloading link %o', link], target: link }
601
- up.event.whenEmitted('up:link:preload', preloadEventAttrs).then ->
602
- variant = up.link.followVariantForLink(link)
603
- variant.preloadLink(link, options)
604
- else
605
- Promise.reject(new Error("Won't preload unsafe link"))
606
-
607
- ###**
608
- This event is [emitted](/up.emit) before a link is [preloaded](/up.preload).
609
-
610
- @event up:link:preload
611
- @param {Element} event.target
612
- The link element that will be preloaded.
613
- @param event.preventDefault()
614
- Event listeners may call this method to prevent the link from being preloaded.
615
- @stable
616
- ###
617
-
618
- ###**
619
- @internal
620
- ###
621
- isSafeMethod = (method) ->
622
- u.contains(config.safeMethods, method)
623
-
624
- ###**
625
- @internal
626
- ###
627
- wrapMethod = (method, params) ->
628
- if u.contains(config.wrapMethods, method)
629
- params.add(up.protocol.config.methodParam, method)
630
- method = 'POST'
631
- method
632
-
633
- ###**
634
- Links with an `up-preload` attribute will silently fetch their target
635
- when the user hovers over the click area, or when the user puts her
636
- mouse/finger down (before releasing).
637
-
638
- When the link is clicked later, the response will already be cached,
639
- making the interaction feel instant.
640
-
641
- @selector a[up-preload]
642
- @param [up-delay=75]
643
- The number of milliseconds to wait between hovering
644
- and preloading. Increasing this will lower the load in your server,
645
- but will also make the interaction feel less instant.
646
- @stable
647
- ###
648
- up.compiler 'a[up-preload], [up-href][up-preload]', (link) ->
649
- if up.link.isSafe(link)
650
- link.addEventListener 'mouseenter', (event) ->
651
- if up.link.shouldProcessEvent(event, link)
652
- preloadAfterDelay(link)
653
- link.addEventListener 'mouseleave', ->
654
- stopPreload(link)
655
-
656
- up.on 'up:framework:reset', reset
657
-
658
- preload: preload
659
- ajax: ajax
660
- request: makeRequest
661
- get: get
662
- alias: alias
663
- clear: clear
664
- remove: remove
665
- isIdle: isIdle
666
- isBusy: isBusy
667
- isSafeMethod: isSafeMethod
668
- wrapMethod: wrapMethod
669
- config: config
670
-
671
- up.ajax = up.proxy.ajax
672
- up.request = up.proxy.request