unpoly-rails 0.62.0 → 2.0.0.pre.rc5

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 +66 -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 +15679 -10537
  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 -313
  37. data/.gitignore +0 -10
  38. data/.ruby-version +0 -1
  39. data/Gemfile +0 -8
  40. data/Gemfile.lock +0 -45
  41. data/Rakefile +0 -145
  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 -240
  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 -64
  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 -445
  95. data/lib/assets/javascripts/unpoly/feedback.coffee +0 -353
  96. data/lib/assets/javascripts/unpoly/form.coffee.erb +0 -1069
  97. data/lib/assets/javascripts/unpoly/fragment.coffee.erb +0 -928
  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 -826
  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 -830
  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 -30
  134. data/spec_app/Gemfile.lock +0 -229
  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 -1527
  305. data/spec_app/spec/javascripts/up/fragment_spec.js.coffee +0 -2611
  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 -1098
  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 -918
  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 -508
  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,67 +0,0 @@
1
- ###**
2
- Toast alerts
3
- ============
4
-
5
- @module up.toast
6
- ###
7
- up.toast = do ->
8
- u = up.util
9
- e = up.element
10
-
11
- VARIABLE_FORMATTER = (arg) -> "<span class='up-toast-variable'>#{u.escapeHtml(arg)}</span>"
12
-
13
- state = new up.Config
14
- element: null
15
-
16
- reset = ->
17
- close()
18
- state.reset()
19
-
20
- messageToHtml = (message) ->
21
- if u.isArray(message)
22
- message[0] = u.escapeHtml(message[0])
23
- message = up.log.sprintfWithFormattedArgs(VARIABLE_FORMATTER, message...)
24
- else
25
- message = u.escapeHtml(message)
26
- message
27
-
28
- isOpen = ->
29
- !!state.element
30
-
31
- addAction = (label, callback) ->
32
- actions = state.element.querySelector('.up-toast-actions')
33
- action = e.affix(actions, '.up-toast-action')
34
- action.innerText = label
35
- action.addEventListener('click', callback)
36
-
37
- open = (message, options = {}) ->
38
- close()
39
-
40
- message = messageToHtml(message)
41
-
42
- state.element = e.createFromHtml """
43
- <div class="up-toast">
44
- <div class="up-toast-message">#{message}</div>
45
- <div class="up-toast-actions"></div>
46
- </div>
47
- """
48
-
49
- if action = (options.action || options.inspect)
50
- addAction(action.label, action.callback)
51
-
52
- addAction('Close', close)
53
-
54
- document.body.appendChild(state.element)
55
-
56
- close = ->
57
- if isOpen()
58
- e.remove(state.element)
59
- state.element = null
60
-
61
- # The framework is reset between tests
62
- up.on 'up:framework:reset', reset
63
-
64
- open: open
65
- close: close
66
- reset: reset
67
- isOpen: isOpen
@@ -1,276 +0,0 @@
1
- ###**
2
- Tooltips
3
- ========
4
-
5
- Unpoly comes with a basic tooltip implementation.
6
-
7
- Add an [`up-tooltip`](/up-tooltip) attribute to any HTML tag to show a tooltip whenever
8
- the user hovers over the element:
9
-
10
- <a href="/decks" up-tooltip="Show all decks">Decks</a>
11
-
12
-
13
- \#\#\# Styling
14
-
15
- The default styles
16
- render a tooltip with white text on a gray background.
17
- A gray triangle points to the element.
18
-
19
- To change the styling, simply override the [CSS rules](https://github.com/unpoly/unpoly/blob/master/lib/assets/stylesheets/unpoly/tooltip.sass) for the `.up-tooltip` selector and its `:after`
20
- selector that is used for the triangle.
21
-
22
- The HTML of a tooltip element looks like this:
23
-
24
- <div class="up-tooltip">
25
- <div class="up-tooltip-content">
26
- Tooltip text here
27
- </div>
28
- </div>
29
-
30
- The tooltip element is appended to the [viewport](/up.viewport) of the anchor element.
31
-
32
- @module up.tooltip
33
- ###
34
- up.tooltip = do ->
35
-
36
- u = up.util
37
- e = up.element
38
-
39
- ###**
40
- Configures defaults for future tooltips.
41
-
42
- @property up.tooltip.config
43
- @param {string} [config.position]
44
- The default position of tooltips relative to the opening element.
45
-
46
- Valid values are `'top'`, `'right'`, `'bottom'` or `'left'`.
47
- @param {string} [config.align]
48
- Defines the alignment of the tooltip along its side.
49
-
50
- When the tooltip's `{ position }` is `'top'` or `'bottom'`, valid `{ align }` values are `'left'`, `center'` and `'right'`.
51
- When the tooltip's `{ position }` is `'left'` or `'right'`, valid `{ align }` values are `top'`, `center'` and `bottom'`.
52
- @param {string} [config.openAnimation='fade-in']
53
- The animation used to open a tooltip.
54
- @param {string} [config.closeAnimation='fade-out']
55
- The animation used to close a tooltip.
56
- @param {number} [config.openDuration]
57
- The duration of the open animation (in milliseconds).
58
- @param {number} [config.closeDuration]
59
- The duration of the close animation (in milliseconds).
60
- @param {string} [config.openEasing]
61
- The timing function controlling the acceleration of the opening animation.
62
- @param {string} [config.closeEasing]
63
- The timing function controlling the acceleration of the closing animation.
64
- @stable
65
- ###
66
- config = new up.Config
67
- position: 'top'
68
- align: 'center'
69
- openAnimation: 'fade-in'
70
- closeAnimation: 'fade-out'
71
- openDuration: 100
72
- closeDuration: 50
73
- openEasing: null
74
- closeEasing: null
75
-
76
- state = new up.Config
77
- phase: 'closed' # can be 'opening', 'opened', 'closing' and 'closed'
78
- anchor: null # the element to which the tooltip is anchored
79
- tooltip: null # the .up-tooltip element
80
- content: null # the .up-tooltip-content element
81
- tether: null # the up.Tether instance controlling the tooltip's position
82
- position: null # the position of the tooltip element relative to its anchor
83
- align: null
84
-
85
- chain = new up.DivertibleChain()
86
-
87
- reset = ->
88
- state.tether?.destroy()
89
- state.reset()
90
- chain.reset()
91
- config.reset()
92
-
93
- createElement = (options) ->
94
- state.tether = new up.Tether(u.only(state, 'anchor', 'position', 'align'))
95
- state.tooltip = e.affix(state.tether.root, '.up-tooltip', 'up-position': state.position, 'up-align': state.align)
96
- state.content = e.affix(state.tooltip, '.up-tooltip-content')
97
-
98
- if options.text
99
- state.content.innerText = options.text
100
- else
101
- state.content.innerHTML = options.html
102
-
103
- ###**
104
- Forces the tooltip to update its position relative to its anchor element.
105
-
106
- Unpoly will automatically keep tooltips aligned when
107
- the document is resized or scrolled. Complex layout changes may make
108
- it necessary to call this function.
109
-
110
- @function up.tooltip.sync
111
- @experimental
112
- ###
113
- syncPosition = ->
114
- state.tether?.sync()
115
-
116
- ###**
117
- Opens a tooltip over the given element.
118
-
119
- The unobtrusive variant of this is the [`[up-tooltip]`](/up-tooltip) selector.
120
-
121
- \#\#\# Examples
122
-
123
- In order to attach a tooltip to a `<span class="help">?</span>`:
124
-
125
- up.tooltip.attach('.help', { text: 'Useful info' })
126
-
127
- @function up.tooltip.attach
128
- @param {Element|jQuery|string} elementOrSelector
129
- @param {string} [options.text]
130
- The text to display in the tooltip.
131
-
132
- Any HTML control characters will be escaped.
133
- If you need to use HTML formatting in the tooltip, use `options.html` instead.
134
- @param {string} [options.html]
135
- The HTML to display in the tooltip unescaped.
136
-
137
- Make sure to escape any user-provided text before passing it as this option,
138
- or use `options.text` (which automatically escapes).
139
- @param {string} [options.position]
140
- The tooltip's position relative to the opening element.
141
-
142
- Valid values are `'top'`, `'right'`, `'bottom'` or `'left'`.
143
- @param {string} [options.align]
144
- Defines the alignment of the tooltip along its side.
145
-
146
- When the tooltip's `{ position }` is `'top'` or `'bottom'`, valid `{ align }` values are `'left'`, `center'` and `'right'`.
147
- When the tooltip's `{ position }` is `'left'` or `'right'`, valid `{ align }` values are `top'`, `center'` and `bottom'`.
148
- @param {string} [options.animation]
149
- The [animation](/up.motion) to use when opening the tooltip.
150
- @return {Promise}
151
- A promise that will be fulfilled when the tooltip's opening animation has finished.
152
- @stable
153
- ###
154
- attachAsap = (elementOrSelector, options) ->
155
- chain.asap closeNow, (-> attachNow(elementOrSelector, options))
156
-
157
- attachNow = (elementOrSelector, options = {}) ->
158
- anchor = e.get(elementOrSelector)
159
- html = options.html ? anchor.getAttribute('up-tooltip-html')
160
- text = options.text ? anchor.getAttribute('up-tooltip')
161
- position = options.position ? anchor.getAttribute('up-position') ? config.position
162
- align = options.align ? anchor.getAttribute('up-align') ? config.align
163
- animation = options.animation ? e.booleanOrStringAttr(anchor, 'up-animation') ? config.openAnimation
164
- animateOptions = up.motion.animateOptions(options, anchor, duration: config.openDuration, easing: config.openEasing)
165
-
166
- state.phase = 'opening'
167
- state.anchor = anchor
168
- state.position = position
169
- state.align = align
170
- createElement({ text, html })
171
- syncPosition()
172
- up.animate(state.tooltip, animation, animateOptions).then ->
173
- state.phase = 'opened'
174
-
175
- ###**
176
- Closes a currently shown tooltip.
177
-
178
- Does nothing if no tooltip is currently shown.
179
-
180
- @function up.tooltip.close
181
- @param {Object} options
182
- See options for [`up.animate()`](/up.animate).
183
- @return {Promise}
184
- A promise for the end of the closing animation.
185
- @stable
186
- ###
187
- closeAsap = (options) ->
188
- chain.asap -> closeNow(options)
189
-
190
- closeNow = (options) ->
191
- unless isOpen() # this can happen when a request fails and the chain proceeds to the next task
192
- return Promise.resolve()
193
-
194
- options = u.options(options, animation: config.closeAnimation)
195
- animateOptions = up.motion.animateOptions(options, duration: config.closeDuration, easing: config.closeEasing)
196
- u.assign(options, animateOptions)
197
- state.phase = 'closing'
198
- up.destroy(state.tooltip, options).then ->
199
- state.phase = 'closed'
200
- state.tether.destroy()
201
- state.tether = null
202
- state.tooltip = null
203
- state.content = null
204
- state.anchor = null
205
-
206
- ###**
207
- Returns whether a tooltip is currently showing.
208
-
209
- @function up.tooltip.isOpen
210
- @stable
211
- ###
212
- isOpen = ->
213
- state.phase == 'opening' || state.phase == 'opened'
214
-
215
- ###**
216
- Displays a tooltip with text content when hovering the mouse over this element.
217
-
218
- \#\#\# Example
219
-
220
- <a href="/decks" up-tooltip="Show all decks">Decks</a>
221
-
222
- To make the tooltip appear below the element instead of above the element,
223
- add an `up-position` attribute:
224
-
225
- <a href="/decks" up-tooltip="Show all decks" up-position="bottom">Decks</a>
226
-
227
- @selector [up-tooltip]
228
- @param {string} [up-animation]
229
- The animation used to open the tooltip.
230
- Defaults to [`up.tooltip.config.openAnimation`](/up.tooltip.config).
231
- @param {string} [up-position]
232
- The tooltip's position relative to the opening element.
233
-
234
- Valid values are `'top'`, `'right'`, `'bottom'` or `'left'`.
235
- @param {string} [up-align]
236
- Defines the alignment of the tooltip along its side.
237
-
238
- When the tooltip's `{ position }` is `'top'` or `'bottom'`, valid `{ align }` values are `'left'`, `center'` and `'right'`.
239
- When the tooltip's `{ position }` is `'left'` or `'right'`, valid `{ align }` values are `top'`, `center'` and `bottom'`.
240
- @stable
241
- ###
242
-
243
- ###**
244
- Displays a tooltip with HTML content when hovering the mouse over this element:
245
-
246
- <a href="/decks" up-tooltip-html="Show &lt;b&gt;all&lt;/b&gt; decks">Decks</a>
247
-
248
- @selector [up-tooltip-html]
249
- @stable
250
- ###
251
- up.compiler '[up-tooltip], [up-tooltip-html]', (opener) ->
252
- # Don't register these events on document since *every*
253
- # mouse move interaction bubbles up to the document.
254
- opener.addEventListener 'mouseenter', -> attachAsap(opener)
255
- opener.addEventListener 'mouseleave', -> closeAsap()
256
-
257
- # We close the tooltip when someone clicks on the document.
258
- # We also need to listen to up:action:consumed in case an [up-instant] link
259
- # was followed on mousedown.
260
- up.on 'click up:action:consumed', (_event) -> # do take an argument so we won't parse [up-data]
261
- closeAsap()
262
- # Do not halt the event chain here. The user is allowed to directly activate
263
- # a link in the background, even with a (now closing) tooltip open.
264
-
265
- # The framework is reset between tests, so also close a currently open tooltip.
266
- up.on 'up:framework:reset', reset
267
-
268
- # Close the tooltip when the user presses ESC.
269
- up.event.onEscape(-> closeAsap())
270
-
271
- config: config
272
- attach: attachAsap
273
- isOpen: isOpen
274
- close: closeAsap
275
- sync: syncPosition
276
-
@@ -1,1676 +0,0 @@
1
- ###**
2
- Utility functions
3
- =================
4
-
5
- The `up.util` module contains functions to facilitate the work with basic JavaScript
6
- values like lists, strings or functions.
7
-
8
- You will recognize many functions form other utility libraries like [Lodash](https://lodash.com/).
9
- While feature parity with Lodash is not a goal of `up.util`, you might find it sufficient
10
- to not include another library in your asset bundle.
11
-
12
- @module up.util
13
- ###
14
- up.util = do ->
15
-
16
- ###**
17
- A function that does nothing.
18
-
19
- @function up.util.noop
20
- @experimental
21
- ###
22
- noop = (->)
23
-
24
- ###**
25
- A function that returns a resolved promise.
26
-
27
- @function up.util.asyncNoop
28
- @internal
29
- ###
30
- asyncNoop = -> Promise.resolve()
31
-
32
- ###**
33
- Ensures that the given function can only be called a single time.
34
- Subsequent calls will return the return value of the first call.
35
-
36
- Note that this is a simple implementation that
37
- doesn't distinguish between argument lists.
38
-
39
- @function up.util.memoize
40
- @internal
41
- ###
42
- memoize = (func) ->
43
- cachedValue = undefined
44
- cached = false
45
- (args...) ->
46
- if cached
47
- cachedValue
48
- else
49
- cached = true
50
- cachedValue = func(args...)
51
-
52
- ###**
53
- Returns if the given port is the default port for the given protocol.
54
-
55
- @function up.util.isStandardPort
56
- @internal
57
- ###
58
- isStandardPort = (protocol, port) ->
59
- port = port.toString()
60
- ((port == "" || port == "80") && protocol == 'http:') || (port == "443" && protocol == 'https:')
61
-
62
- ###**
63
- Normalizes relative paths and absolute paths to a full URL
64
- that can be checked for equality with other normalized URLs.
65
-
66
- By default hashes are ignored, search queries are included.
67
-
68
- @function up.util.normalizeUrl
69
- @param {boolean} [options.hash=false]
70
- Whether to include an `#hash` anchor in the normalized URL
71
- @param {boolean} [options.search=true]
72
- Whether to include a `?query` string in the normalized URL
73
- @param {boolean} [options.stripTrailingSlash=false]
74
- Whether to strip a trailing slash from the pathname
75
- @internal
76
- ###
77
- normalizeUrl = (urlOrAnchor, options) ->
78
- parts = parseUrl(urlOrAnchor)
79
- normalized = parts.protocol + "//" + parts.hostname
80
- normalized += ":#{parts.port}" unless isStandardPort(parts.protocol, parts.port)
81
- pathname = parts.pathname
82
- pathname = pathname.replace(/\/$/, '') if options?.stripTrailingSlash == true
83
- normalized += pathname
84
- normalized += parts.search unless options?.search == false
85
- normalized += parts.hash if options?.hash == true
86
- normalized
87
-
88
- isCrossDomain = (targetUrl) ->
89
- currentUrl = parseUrl(location.href)
90
- targetUrl = parseUrl(targetUrl)
91
- currentUrl.protocol != targetUrl.protocol || currentUrl.hostname != targetUrl.hostname
92
-
93
- ###**
94
- Parses the given URL into components such as hostname and path.
95
-
96
- If the given URL is not fully qualified, it is assumed to be relative
97
- to the current page.
98
-
99
- @function up.util.parseUrl
100
- @return {Object}
101
- The parsed URL as an object with
102
- `protocol`, `hostname`, `port`, `pathname`, `search` and `hash`
103
- properties.
104
- @stable
105
- ###
106
- parseUrl = (urlOrLink) ->
107
- if isJQuery(urlOrLink)
108
- # In case someone passed us a $link, unwrap it
109
- link = up.element.get(urlOrLink)
110
- else if urlOrLink.pathname
111
- # If we are handed a parsed URL, just return it
112
- link = urlOrLink
113
- else
114
- link = document.createElement('a')
115
- link.href = urlOrLink
116
-
117
- # In IE11 the #hostname and #port properties of unqualified URLs are empty strings.
118
- # We can fix this by setting the link's { href } on the link itself.
119
- unless link.hostname
120
- link.href = link.href
121
-
122
- # Some IEs don't include a leading slash in the #pathname property.
123
- # We have confirmed this in IE11 and earlier.
124
- unless link.pathname[0] == '/'
125
- # Only copy the link into an object when we need to (to change a property).
126
- # Note that we're parsing a lot of URLs for [up-active].
127
- link = only(link, 'protocol', 'hostname', 'port', 'pathname', 'search', 'hash')
128
- link.pathname = '/' + link.pathname
129
-
130
- link
131
-
132
- ###**
133
- @function up.util.normalizeMethod
134
- @internal
135
- ###
136
- normalizeMethod = (method) ->
137
- if method
138
- method.toUpperCase()
139
- else
140
- 'GET'
141
-
142
- ###**
143
- @function up.util.methodAllowsPayload
144
- @internal
145
- ###
146
- methodAllowsPayload = (method) ->
147
- method != 'GET' && method != 'HEAD'
148
-
149
- assignPolyfill = (target, sources...) ->
150
- for source in sources
151
- for own key, value of source
152
- target[key] = value
153
- target
154
-
155
- ###**
156
- Merge the own properties of one or more `sources` into the `target` object.
157
-
158
- @function up.util.assign
159
- @param {Object} target
160
- @param {Array<Object>} sources...
161
- @stable
162
- ###
163
- assign = Object.assign || assignPolyfill
164
-
165
- valuesPolyfill = (object) ->
166
- value for key, value of object
167
-
168
- ###**
169
- Returns an array of values of the given object.
170
-
171
- @function up.util.values
172
- @param {Object} object
173
- @return {Array<string>}
174
- @stable
175
- ###
176
- objectValues = Object.values || valuesPolyfill
177
-
178
- iteratee = (block) ->
179
- if isString(block)
180
- (item) -> item[block]
181
- else
182
- block
183
-
184
- ###**
185
- Translate all items in an array to new array of items.
186
-
187
- @function up.util.map
188
- @param {Array} array
189
- @param {Function(element, index): any|String} block
190
- A function that will be called with each element and (optional) iteration index.
191
-
192
- You can also pass a property name as a String,
193
- which will be collected from each item in the array.
194
- @return {Array}
195
- A new array containing the result of each function call.
196
- @stable
197
- ###
198
- map = (array, block) ->
199
- return [] if array.length == 0
200
- block = iteratee(block)
201
- for item, index in array
202
- block(item, index)
203
-
204
- ###**
205
- @function up.util.mapObject
206
- @internal
207
- ###
208
- mapObject = (array, pairer) ->
209
- merger = (object, pair) ->
210
- object[pair[0]] = pair[1]
211
- return object
212
- map(array, pairer).reduce(merger, {})
213
-
214
- ###**
215
- Calls the given function for each element (and, optional, index)
216
- of the given array.
217
-
218
- @function up.util.each
219
- @param {Array} array
220
- @param {Function(element, index)} block
221
- A function that will be called with each element and (optional) iteration index.
222
- @stable
223
- ###
224
- each = map # note that the native Array.forEach is very slow (https://jsperf.com/fast-array-foreach)
225
-
226
- eachIterator = (iterator, callback) ->
227
- while (entry = iterator.next()) && !entry.done
228
- callback(entry.value)
229
-
230
- ###**
231
- Calls the given function for the given number of times.
232
-
233
- @function up.util.times
234
- @param {number} count
235
- @param {Function()} block
236
- @stable
237
- ###
238
- times = (count, block) ->
239
- block(iteration) for iteration in [0..(count - 1)]
240
-
241
- ###**
242
- Returns whether the given argument is `null`.
243
-
244
- @function up.util.isNull
245
- @param object
246
- @return {boolean}
247
- @stable
248
- ###
249
- isNull = (object) ->
250
- object == null
251
-
252
- ###**
253
- Returns whether the given argument is `undefined`.
254
-
255
- @function up.util.isUndefined
256
- @param object
257
- @return {boolean}
258
- @stable
259
- ###
260
- isUndefined = (object) ->
261
- object == undefined
262
-
263
- ###**
264
- Returns whether the given argument is not `undefined`.
265
-
266
- @function up.util.isDefined
267
- @param object
268
- @return {boolean}
269
- @stable
270
- ###
271
- isDefined = (object) ->
272
- !isUndefined(object)
273
-
274
- ###**
275
- Returns whether the given argument is either `undefined` or `null`.
276
-
277
- Note that empty strings or zero are *not* considered to be "missing".
278
-
279
- For the opposite of `up.util.isMissing()` see [`up.util.isGiven()`](/up.util.isGiven).
280
-
281
- @function up.util.isMissing
282
- @param object
283
- @return {boolean}
284
- @stable
285
- ###
286
- isMissing = (object) ->
287
- isUndefined(object) || isNull(object)
288
-
289
- ###**
290
- Returns whether the given argument is neither `undefined` nor `null`.
291
-
292
- Note that empty strings or zero *are* considered to be "given".
293
-
294
- For the opposite of `up.util.isGiven()` see [`up.util.isMissing()`](/up.util.isMissing).
295
-
296
- @function up.util.isGiven
297
- @param object
298
- @return {boolean}
299
- @stable
300
- ###
301
- isGiven = (object) ->
302
- !isMissing(object)
303
-
304
- # isNan = (object) ->
305
- # isNumber(value) && value != +value
306
-
307
- ###**
308
- Return whether the given argument is considered to be blank.
309
-
310
- By default, this function returns `true` for:
311
-
312
- - `undefined`
313
- - `null`
314
- - Empty strings
315
- - Empty arrays
316
- - A plain object without own enumerable properties
317
-
318
- All other arguments return `false`.
319
-
320
- To check implement blank-ness checks for user-defined classes,
321
- see `up.util.isBlank.key`.
322
-
323
- @function up.util.isBlank
324
- @param value
325
- The value is to check.
326
- @return {boolean}
327
- Whether the value is blank.
328
- @stable
329
- ###
330
- isBlank = (value) ->
331
- if isMissing(value)
332
- return true
333
- if isObject(value) && value[isBlank.key]
334
- return value[isBlank.key]()
335
- if isString(value) || isList(value)
336
- return value.length == 0
337
- if isOptions(value)
338
- return Object.keys(value).length == 0
339
- return false
340
-
341
- ###**
342
- This property contains the name of a method that user-defined classes
343
- may implement to hook into the `up.util.isBlank()` protocol.
344
-
345
- \#\#\# Example
346
-
347
- We have a user-defined `Account` class that we want to use with `up.util.isBlank()`:
348
-
349
- ```
350
- class Account {
351
- constructor(email) {
352
- this.email = email
353
- }
354
-
355
- [up.util.isBlank.key]() {
356
- return up.util.isBlank(this.email)
357
- }
358
- }
359
- ```
360
-
361
- Note that the protocol method is not actually named `'up.util.isBlank.key'`.
362
- Instead it is named after the *value* of the `up.util.isBlank.key` property.
363
- To do so, the code sample above is using a
364
- [computed property name](https://medium.com/front-end-weekly/javascript-object-creation-356e504173a8)
365
- in square brackets.
366
-
367
- We may now use `Account` instances with `up.util.isBlank()`:
368
-
369
- ```
370
- foo = new Account('foo@foo.com')
371
- bar = new Account('')
372
-
373
- console.log(up.util.isBlank(foo)) // prints false
374
- console.log(up.util.isBlank(bar)) // prints true
375
- ```
376
-
377
- @property up.util.isBlank.key
378
- @experimental
379
- ###
380
- isBlank.key = 'up.util.isBlank'
381
-
382
- ###**
383
- Returns the given argument if the argument is [present](/up.util.isPresent),
384
- otherwise returns `undefined`.
385
-
386
- @function up.util.presence
387
- @param value
388
- @param {Function(value): boolean} [tester=up.util.isPresent]
389
- The function that will be used to test whether the argument is present.
390
- @return {any|undefined}
391
- @stable
392
- ###
393
- presence = (value, tester = isPresent) ->
394
- if tester(value) then value else undefined
395
-
396
- ###**
397
- Returns whether the given argument is not [blank](/up.util.isBlank).
398
-
399
- @function up.util.isPresent
400
- @param object
401
- @return {boolean}
402
- @stable
403
- ###
404
- isPresent = (object) ->
405
- !isBlank(object)
406
-
407
- ###**
408
- Returns whether the given argument is a function.
409
-
410
- @function up.util.isFunction
411
- @param object
412
- @return {boolean}
413
- @stable
414
- ###
415
- isFunction = (object) ->
416
- typeof(object) == 'function'
417
-
418
- ###**
419
- Returns whether the given argument is a string.
420
-
421
- @function up.util.isString
422
- @param object
423
- @return {boolean}
424
- @stable
425
- ###
426
- isString = (object) ->
427
- typeof(object) == 'string' || object instanceof String
428
-
429
- ###**
430
- Returns whether the given argument is a boolean value.
431
-
432
- @function up.util.isBoolean
433
- @param object
434
- @return {boolean}
435
- @stable
436
- ###
437
- isBoolean = (object) ->
438
- typeof(object) == 'boolean' || object instanceof Boolean
439
-
440
- ###**
441
- Returns whether the given argument is a number.
442
-
443
- Note that this will check the argument's *type*.
444
- It will return `false` for a string like `"123"`.
445
-
446
- @function up.util.isNumber
447
- @param object
448
- @return {boolean}
449
- @stable
450
- ###
451
- isNumber = (object) ->
452
- typeof(object) == 'number' || object instanceof Number
453
-
454
- ###**
455
- Returns whether the given argument is an options hash,
456
-
457
- Differently from [`up.util.isObject()`], this returns false for
458
- functions, jQuery collections, promises, `FormData` instances and arrays.
459
-
460
- @function up.util.isOptions
461
- @param object
462
- @return {boolean}
463
- @internal
464
- ###
465
- isOptions = (object) ->
466
- typeof(object) == 'object' && !isNull(object) && (isUndefined(object.constructor) || object.constructor == Object)
467
-
468
- ###**
469
- Returns whether the given argument is an object.
470
-
471
- This also returns `true` for functions, which may behave like objects in JavaScript.
472
-
473
- @function up.util.isObject
474
- @param object
475
- @return {boolean}
476
- @stable
477
- ###
478
- isObject = (object) ->
479
- typeOfResult = typeof(object)
480
- (typeOfResult == 'object' && !isNull(object)) || typeOfResult == 'function'
481
-
482
- ###**
483
- Returns whether the given argument is a [DOM element](https://developer.mozilla.org/de/docs/Web/API/Element).
484
-
485
- @function up.util.isElement
486
- @param object
487
- @return {boolean}
488
- @stable
489
- ###
490
- isElement = (object) ->
491
- object instanceof Element
492
-
493
- ###**
494
- Returns whether the given argument is a [jQuery collection](https://learn.jquery.com/using-jquery-core/jquery-object/).
495
-
496
- @function up.util.isJQuery
497
- @param object
498
- @return {boolean}
499
- @stable
500
- ###
501
- isJQuery = (object) ->
502
- # We cannot do `object instanceof jQuery` since window.jQuery might not be set
503
- !!object?.jquery
504
-
505
- ###**
506
- Returns whether the given argument is an object with a `then` method.
507
-
508
- @function up.util.isPromise
509
- @param object
510
- @return {boolean}
511
- @stable
512
- ###
513
- isPromise = (object) ->
514
- isObject(object) && isFunction(object.then)
515
-
516
- ###**
517
- Returns whether the given argument is an array.
518
-
519
- @function up.util.isArray
520
- @param object
521
- @return {boolean}
522
- @stable
523
- ###
524
- # https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
525
- isArray = Array.isArray
526
-
527
- ###**
528
- Returns whether the given argument is a `FormData` instance.
529
-
530
- Always returns `false` in browsers that don't support `FormData`.
531
-
532
- @function up.util.isFormData
533
- @param object
534
- @return {boolean}
535
- @internal
536
- ###
537
- isFormData = (object) ->
538
- object instanceof FormData
539
-
540
- ###**
541
- Converts the given [array-like value](/up.util.isList) into an array.
542
-
543
- If the given value is already an array, it is returned unchanged.
544
-
545
- @function up.util.toArray
546
- @param object
547
- @return {Array}
548
- @stable
549
- ###
550
- toArray = (value) ->
551
- if isArray(value)
552
- value
553
- else
554
- Array.prototype.slice.call(value)
555
-
556
- ###***
557
- Returns whether the given argument is an array-like value.
558
-
559
- Return true for `Array`, a
560
- [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList),
561
- the [arguments object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments)
562
- or a jQuery collection.
563
-
564
- Use [`up.util.isArray()`](/up.util.isArray) to test whether a value is an actual `Array`.
565
-
566
- @function up.util.isList
567
- @param value
568
- @return {Boolean}
569
- @experimental
570
- ###
571
- isList = (value) ->
572
- isArray(value) ||
573
- isNodeList(value) ||
574
- isArguments(value) ||
575
- isJQuery(value) ||
576
- isHTMLCollection(value)
577
-
578
- ###**
579
- Returns whether the given value is a [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList).
580
-
581
- `NodeLists` are array-like objects returned by [`document.querySelectorAll()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll).
582
-
583
- @function up.util.isNodeList
584
- @param value
585
- @return {Boolean}
586
- @internal
587
- ###
588
- isNodeList = (value) ->
589
- value instanceof NodeList
590
-
591
- isHTMLCollection = (value) ->
592
- value instanceof HTMLCollection
593
-
594
- # ###**
595
- # Returns whether the given value is an [`HTMLCollection`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection).
596
- #
597
- # @function up.util.isHtmlCollection
598
- # @param value
599
- # @return {Boolean}
600
- # @experimental
601
- # ###
602
- # isHtmlCollection = (value) ->
603
- # value instanceof HTMLCollection
604
-
605
- ###**
606
- Returns whether the given value is an [arguments object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments).
607
-
608
- @function up.util.isArguments
609
- @param value
610
- @return {Boolean}
611
- @internal
612
- ###
613
- isArguments = (value) ->
614
- Object.prototype.toString.call(value) == '[object Arguments]'
615
-
616
- ###**
617
- @function up.util.wrapList
618
- @return {Array|NodeList|jQuery}
619
- @internal
620
- ###
621
- wrapList = (value) ->
622
- if isList(value)
623
- value
624
- else if isMissing(value)
625
- []
626
- else
627
- [value]
628
-
629
- ###**
630
- Returns a shallow copy of the given value.
631
-
632
- \#\#\# Copying protocol
633
-
634
- - By default `up.util.copy()` can copy [array-like values](/up.util.isList),
635
- plain objects and `Date` instances.
636
- - Array-like objects are copied into new arrays.
637
- - Unsupported types of values are returned unchanged.
638
- - To make the copying protocol work with user-defined class,
639
- see `up.util.copy.key`.
640
- - Immutable objects, like strings or numbers, do not need to be copied.
641
-
642
- @function up.util.copy
643
- @param {any} object
644
- @return {any}
645
- @stable
646
- ###
647
- copy = (value, deep) ->
648
- if isObject(value) && value[copy.key]
649
- value = value[copy.key]()
650
- else if isList(value)
651
- value = Array.prototype.slice.call(value)
652
- copied = true
653
- else if isOptions(value)
654
- value = assign({}, value)
655
- copied = true
656
- if copied && deep
657
- for k, v of value
658
- value[k] = copy(v, true)
659
- value
660
-
661
- ###**
662
- This property contains the name of a method that user-defined classes
663
- may implement to hook into the `up.util.copy()` protocol.
664
-
665
- \#\#\# Example
666
-
667
- We have a user-defined `Account` class that we want to use with `up.util.copy()`:
668
-
669
- ```
670
- class Account {
671
- constructor(email) {
672
- this.email = email
673
- }
674
-
675
- [up.util.copy.key]() {
676
- return new Account(this.email)
677
- }
678
- }
679
- ```
680
-
681
- Note that the protocol method is not actually named `'up.util.copy.key'`.
682
- Instead it is named after the *value* of the `up.util.copy.key` property.
683
- To do so, the code sample above is using a
684
- [computed property name](https://medium.com/front-end-weekly/javascript-object-creation-356e504173a8)
685
- in square brackets.
686
-
687
- We may now use `Account` instances with `up.util.copy()`:
688
-
689
- ```
690
- original = new User('foo@foo.com')
691
-
692
- copy = up.util.copy(original)
693
- console.log(copy.email) // prints 'foo@foo.com'
694
-
695
- original.email = 'bar@bar.com' // change the original
696
- console.log(copy.email) // still prints 'foo@foo.com'
697
- ```
698
-
699
- @property up.util.copy.key
700
- @param {string} key
701
- @experimental
702
- ###
703
- copy.key = 'up.util.copy'
704
-
705
- # Implement up.util.copy protocol for Date
706
- Date.prototype[copy.key] = -> new Date(+@)
707
-
708
- ###**
709
- Returns a deep copy of the given array or object.
710
-
711
- @function up.util.deepCopy
712
- @param {Object|Array} object
713
- @return {Object|Array}
714
- @internal
715
- ###
716
- deepCopy = (object) ->
717
- copy(object, true)
718
-
719
- ###**
720
- Creates a new object by merging together the properties from the given objects.
721
-
722
- @function up.util.merge
723
- @param {Array<Object>} sources...
724
- @return Object
725
- @stable
726
- ###
727
- merge = (sources...) ->
728
- assign({}, sources...)
729
-
730
- # ###**
731
- # Creates a new object by recursively merging together the properties from the given objects.
732
- #
733
- # @function up.util.deepMerge
734
- # @param {Array<Object>} sources...
735
- # @return Object
736
- #
737
- # @internal
738
- # ###
739
- # deepMerge = (sources...) ->
740
- # deepAssign({}, sources...)
741
- #
742
- # ###**
743
- # @function up.util.deepAssign
744
- # @param {Array<Object>} sources...
745
- # @return Object
746
- # ###
747
- # deepAssign = (target, sources...) ->
748
- # for source in sources
749
- # for key, newValue of source
750
- # if isOptions(newValue)
751
- # oldValue = target[key]
752
- # if isOptions(oldValue)
753
- # newValue = deepMerge(oldValue, newValue)
754
- # target[key] = newValue
755
- # target
756
-
757
- ###**
758
- Creates an options hash from the given argument and some defaults.
759
-
760
- The semantics of this function are confusing.
761
- We want to get rid of this in the future.
762
-
763
- @function up.util.options
764
- @param {Object} object
765
- @param {Object} [defaults]
766
- @return {Object}
767
- @internal
768
- ###
769
- newOptions = (object, defaults) ->
770
- if defaults
771
- merge(defaults, object)
772
- else if object
773
- copy(object)
774
- else
775
- {}
776
-
777
- ###**
778
- Passes each element in the given [array-like value](/up.util.isList) to the given function.
779
- Returns the first element for which the function returns a truthy value.
780
-
781
- If no object matches, returns `undefined`.
782
-
783
- @function up.util.find
784
- @param {List<T>} list
785
- @param {Function(value): boolean} tester
786
- @return {T|undefined}
787
- @stable
788
- ###
789
- findInList = (list, tester) ->
790
- match = undefined
791
- for element in list
792
- if tester(element)
793
- match = element
794
- break
795
- match
796
-
797
- ###**
798
- Returns whether the given function returns a truthy value
799
- for any element in the given [array-like value](/up.util.isList).
800
-
801
- @function up.util.some
802
- @param {List} list
803
- @param {Function(value, index): boolean} tester
804
- A function that will be called with each element and (optional) iteration index.
805
-
806
- @return {boolean}
807
- @stable
808
- ###
809
- some = (list, tester) ->
810
- !!findResult(list, tester)
811
-
812
- ###**
813
- Consecutively calls the given function which each element
814
- in the given array. Returns the first truthy return value.
815
-
816
- Returned `undefined` iff the function does not return a truthy
817
- value for any element in the array.
818
-
819
- @function up.util.findResult
820
- @param {Array} array
821
- @param {Function(element): any} tester
822
- A function that will be called with each element and (optional) iteration index.
823
-
824
- @return {any|undefined}
825
- @experimental
826
- ###
827
- findResult = (array, tester) ->
828
- tester = iteratee(tester)
829
- for element, index in array
830
- if result = tester(element, index)
831
- return result
832
- return undefined
833
-
834
- ###**
835
- Returns whether the given function returns a truthy value
836
- for all elements in the given [array-like value](/up.util.isList).
837
-
838
- @function up.util.every
839
- @param {List} list
840
- @param {Function(element, index): boolean} tester
841
- A function that will be called with each element and (optional) iteration index.
842
-
843
- @return {boolean}
844
- @experimental
845
- ###
846
- every = (list, tester) ->
847
- tester = iteratee(tester)
848
- match = true
849
- for element, index in list
850
- unless tester(element, index)
851
- match = false
852
- break
853
- match
854
-
855
- ###**
856
- Returns all elements from the given array that are
857
- neither `null` or `undefined`.
858
-
859
- @function up.util.compact
860
- @param {Array<T>} array
861
- @return {Array<T>}
862
- @stable
863
- ###
864
- compact = (array) ->
865
- filterList array, isGiven
866
-
867
- ###**
868
- Returns the given array without duplicates.
869
-
870
- @function up.util.uniq
871
- @param {Array<T>} array
872
- @return {Array<T>}
873
- @stable
874
- ###
875
- uniq = (array) ->
876
- return array if array.length < 2
877
- setToArray(arrayToSet(array))
878
-
879
- ###**
880
- This function is like [`uniq`](/up.util.uniq), accept that
881
- the given function is invoked for each element to generate the value
882
- for which uniquness is computed.
883
-
884
- @function up.util.uniqBy
885
- @param {Array} array
886
- @param {Function(value): any} array
887
- @return {Array}
888
- @experimental
889
- ###
890
- uniqBy = (array, mapper) ->
891
- return array if array.length < 2
892
- mapper = iteratee(mapper)
893
- set = new Set()
894
- filterList array, (elem, index) ->
895
- mapped = mapper(elem, index)
896
- if set.has(mapped)
897
- false
898
- else
899
- set.add(mapped)
900
- true
901
-
902
- ###**
903
- @function up.util.setToArray
904
- @internal
905
- ###
906
- setToArray = (set) ->
907
- array = []
908
- set.forEach (elem) -> array.push(elem)
909
- array
910
-
911
- ###**
912
- @function up.util.arrayToSet
913
- @internal
914
- ###
915
- arrayToSet = (array) ->
916
- set = new Set()
917
- array.forEach (elem) -> set.add(elem)
918
- set
919
-
920
- ###**
921
- Returns all elements from the given [array-like value](/up.util.isList) that return
922
- a truthy value when passed to the given function.
923
-
924
- @function up.util.filter
925
- @param {List} list
926
- @param {Function(value, index): boolean} tester
927
- @return {Array}
928
- @stable
929
- ###
930
- filterList = (list, tester) ->
931
- tester = iteratee(tester)
932
- matches = []
933
- each list, (element, index) ->
934
- if tester(element, index)
935
- matches.push(element)
936
- matches
937
-
938
- ###**
939
- Returns all elements from the given [array-like value](/up.util.isList) that do not return
940
- a truthy value when passed to the given function.
941
-
942
- @function up.util.reject
943
- @param {List} list
944
- @param {Function(element, index): boolean} tester
945
- @return {Array}
946
- @stable
947
- ###
948
- reject = (list, tester) ->
949
- tester = iteratee(tester)
950
- filterList(list, (element, index) -> !tester(element, index))
951
-
952
- ###**
953
- Returns the intersection of the given two arrays.
954
-
955
- Implementation is not optimized. Don't use it for large arrays.
956
-
957
- @function up.util.intersect
958
- @internal
959
- ###
960
- intersect = (array1, array2) ->
961
- filterList array1, (element) ->
962
- contains(array2, element)
963
-
964
- ###**
965
- Waits for the given number of milliseconds, the runs the given callback.
966
-
967
- Instead of `up.util.timer(0, fn)` you can also use [`up.util.task(fn)`](/up.util.task).
968
-
969
- @function up.util.timer
970
- @param {number} millis
971
- @param {Function()} callback
972
- @stable
973
- ###
974
- scheduleTimer = (millis, callback) ->
975
- setTimeout(callback, millis)
976
-
977
- ###**
978
- Pushes the given function to the [JavaScript task queue](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) (also "macrotask queue").
979
-
980
- Equivalent to calling `setTimeout(fn, 0)`.
981
-
982
- Also see `up.util.microtask()`.
983
-
984
- @function up.util.task
985
- @param {Function()} block
986
- @stable
987
- ###
988
- queueTask = (block) ->
989
- setTimeout(block, 0)
990
-
991
- ###**
992
- Pushes the given function to the [JavaScript microtask queue](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/).
993
-
994
- @function up.util.microtask
995
- @param {Function()} task
996
- @return {Promise}
997
- @experimental
998
- ###
999
- queueMicrotask = (task) ->
1000
- Promise.resolve().then(task)
1001
-
1002
- ###**
1003
- Returns the last element of the given array.
1004
-
1005
- @function up.util.last
1006
- @param {Array<T>} array
1007
- @return {T}
1008
- ###
1009
- last = (array) ->
1010
- array[array.length - 1]
1011
-
1012
- ###**
1013
- Returns whether the given keyboard event involved the ESC key.
1014
-
1015
- @function up.util.escapePressed
1016
- @internal
1017
- ###
1018
- escapePressed = (event) ->
1019
- key = event.key
1020
- key == 'Escape' || key == 'Esc'
1021
-
1022
- ###**
1023
- Returns whether the given array or string contains the given element or substring.
1024
-
1025
- @function up.util.contains
1026
- @param {Array|string} arrayOrString
1027
- @param elementOrSubstring
1028
- @stable
1029
- ###
1030
- contains = (arrayOrString, elementOrSubstring) ->
1031
- arrayOrString.indexOf(elementOrSubstring) >= 0
1032
-
1033
- ###**
1034
- Returns a copy of the given object that only contains
1035
- the given properties.
1036
-
1037
- @function up.util.only
1038
- @param {Object} object
1039
- @param {Array} keys...
1040
- @stable
1041
- ###
1042
- only = (object, properties...) ->
1043
- filtered = {}
1044
- for property in properties
1045
- if property of object
1046
- filtered[property] = object[property]
1047
- filtered
1048
-
1049
- ###**
1050
- Returns a copy of the given object that contains all except
1051
- the given properties.
1052
-
1053
- @function up.util.except
1054
- @param {Object} object
1055
- @param {Array} keys...
1056
- @stable
1057
- ###
1058
- except = (object, properties...) ->
1059
- filtered = copy(object)
1060
- for property in properties
1061
- delete filtered[property]
1062
- filtered
1063
-
1064
- # pickBy = (obj, predicate) ->
1065
- # result = {}
1066
- # for k, v of obj
1067
- # if predicate(v, k)
1068
- # result[k] = v
1069
- # result
1070
-
1071
- ###**
1072
- @function up.util.isUnmodifiedKeyEvent
1073
- @internal
1074
- ###
1075
- isUnmodifiedKeyEvent = (event) ->
1076
- not (event.metaKey or event.shiftKey or event.ctrlKey)
1077
-
1078
- ###**
1079
- @function up.util.isUnmodifiedMouseEvent
1080
- @internal
1081
- ###
1082
- isUnmodifiedMouseEvent = (event) ->
1083
- isLeftButton = isUndefined(event.button) || event.button == 0
1084
- isLeftButton && isUnmodifiedKeyEvent(event)
1085
-
1086
- ###**
1087
- Returns a promise that will never be resolved.
1088
-
1089
- @function up.util.unresolvablePromise
1090
- @internal
1091
- ###
1092
- unresolvablePromise = ->
1093
- new Promise(noop)
1094
-
1095
- ###**
1096
- Removes the given element from the given array.
1097
-
1098
- This changes the given array.
1099
-
1100
- @function up.util.remove
1101
- @param {Array<T>} array
1102
- @param {T} element
1103
- @stable
1104
- ###
1105
- remove = (array, element) ->
1106
- index = array.indexOf(element)
1107
- if index >= 0
1108
- array.splice(index, 1)
1109
- element
1110
-
1111
- ###**
1112
- If the given `value` is a function, calls the function with the given `args`.
1113
- Otherwise it just returns `value`.
1114
-
1115
- @function up.util.evalOption
1116
- @internal
1117
- ###
1118
- evalOption = (value, args...) ->
1119
- if isFunction(value)
1120
- value(args...)
1121
- else
1122
- value
1123
-
1124
- ###**
1125
- Throws a [JavaScript error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
1126
- with the given message.
1127
-
1128
- The message will also be printed to the [error log](/up.log.error). Also a notification will be shown at the bottom of the screen.
1129
-
1130
- The message may contain [substitution marks](https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions).
1131
-
1132
- \#\#\# Examples
1133
-
1134
- up.fail('Division by zero')
1135
- up.fail('Unexpected result %o', result)
1136
-
1137
- @function up.fail
1138
- @param {string} message
1139
- A message with details about the error.
1140
-
1141
- The message can contain [substitution marks](https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions)
1142
- like `%s` or `%o`.
1143
- @param {Array<string>} vars...
1144
- A list of variables to replace any substitution marks in the error message.
1145
- @experimental
1146
- ###
1147
- fail = (args...) ->
1148
- if isArray(args[0])
1149
- messageArgs = args[0]
1150
- toastOptions = args[1] || {}
1151
- else
1152
- messageArgs = args
1153
- toastOptions = {}
1154
-
1155
- up.log.error(messageArgs...)
1156
-
1157
- up.event.onReady(-> up.toast.open(messageArgs, toastOptions))
1158
-
1159
- asString = up.log.sprintf(messageArgs...)
1160
- throw new Error(asString)
1161
-
1162
- ESCAPE_HTML_ENTITY_MAP =
1163
- "&": "&amp;"
1164
- "<": "&lt;"
1165
- ">": "&gt;"
1166
- '"': '&quot;'
1167
-
1168
- ###**
1169
- Escapes the given string of HTML by replacing control chars with their HTML entities.
1170
-
1171
- @function up.util.escapeHtml
1172
- @param {string} string
1173
- The text that should be escaped
1174
- @stable
1175
- ###
1176
- escapeHtml = (string) ->
1177
- string.replace /[&<>"]/g, (char) -> ESCAPE_HTML_ENTITY_MAP[char]
1178
-
1179
- ###**
1180
- @function up.util.escapeRegexp
1181
- @internal
1182
- ###
1183
- escapeRegexp = (string) ->
1184
- # From https://github.com/benjamingr/RegExp.escape
1185
- string.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&')
1186
-
1187
- pluckKey = (object, key) ->
1188
- value = object[key]
1189
- delete object[key]
1190
- value
1191
-
1192
- renameKey = (object, oldKey, newKey) ->
1193
- object[newKey] = pluckKey(object, oldKey)
1194
-
1195
- extractLastArg = (args, tester) ->
1196
- lastArg = last(args)
1197
- if tester(lastArg)
1198
- return args.pop()
1199
-
1200
- # extractFirstArg = (args, tester) ->
1201
- # firstArg = args[0]
1202
- # if tester(firstArg)
1203
- # return args.shift()
1204
-
1205
- extractCallback = (args) ->
1206
- extractLastArg(args, isFunction)
1207
-
1208
- extractOptions = (args) ->
1209
- extractLastArg(args, isOptions) || {}
1210
-
1211
- partial = (fn, fixedArgs...) ->
1212
- return (callArgs...) ->
1213
- fn.apply(this, fixedArgs.concat(callArgs))
1214
-
1215
- #function throttle(callback, limit) { // From https://jsfiddle.net/jonathansampson/m7G64/
1216
- # var wait = false // Initially, we're not waiting
1217
- # return function () { // We return a throttled function
1218
- # if (!wait) { // If we're not waiting
1219
- # callback.call() // Execute users function
1220
- # wait = true // Prevent future invocations
1221
- # setTimeout(function () { // After a period of time
1222
- # wait = false // And allow future invocations
1223
- # }, limit)
1224
- # }
1225
- # }
1226
- #}
1227
-
1228
- identity = (arg) -> arg
1229
-
1230
- # ###**
1231
- # ###
1232
- # parsePath = (input) ->
1233
- # path = []
1234
- # pattern = /([^\.\[\]\"\']+)|\[\'([^\']+?)\'\]|\[\"([^\"]+?)\"\]|\[([^\]]+?)\]/g
1235
- # while match = pattern.exec(input)
1236
- # path.push(match[1] || match[2] || match[3] || match[4])
1237
- # path
1238
-
1239
- ###**
1240
- Given a function that will return a promise, returns a proxy function
1241
- with an additional `.promise` attribute.
1242
-
1243
- When the proxy is called, the inner function is called.
1244
- The proxy's `.promise` attribute is available even before the function is called
1245
- and will resolve when the inner function's returned promise resolves.
1246
-
1247
- If the inner function does not return a promise, the proxy's `.promise` attribute
1248
- will resolve as soon as the inner function returns.
1249
-
1250
- @function up.util.previewable
1251
- @internal
1252
- ###
1253
- previewable = (fun) ->
1254
- deferred = newDeferred()
1255
- preview = (args...) ->
1256
- funValue = fun(args...)
1257
- # If funValue is again a Promise, it will defer resolution of `deferred`
1258
- # until `funValue` is resolved.
1259
- deferred.resolve(funValue)
1260
- funValue
1261
- preview.promise = deferred.promise()
1262
- preview
1263
-
1264
- ###**
1265
- @function up.util.sequence
1266
- @param {Array<Function()>} functions
1267
- @return {Function()}
1268
- A function that will call all `functions` if called.
1269
-
1270
- @internal
1271
- ###
1272
- sequence = (functions) ->
1273
- if functions.length == 1
1274
- return functions[0]
1275
- else
1276
- return -> map(functions, (f) -> f())
1277
-
1278
- # ###**
1279
- # @function up.util.race
1280
- # @internal
1281
- # ###
1282
- # race = (promises...) ->
1283
- # raceDone = newDeferred()
1284
- # each promises, (promise) ->
1285
- # promise.then -> raceDone.resolve()
1286
- # raceDone.promise()
1287
-
1288
- ###**
1289
- Returns `'left'` if the center of the given element is in the left 50% of the screen.
1290
- Otherwise returns `'right'`.
1291
-
1292
- @function up.util.horizontalScreenHalf
1293
- @internal
1294
- ###
1295
- horizontalScreenHalf = (element) ->
1296
- elementDims = element.getBoundingClientRect()
1297
- elementMid = elementDims.left + 0.5 * elementDims.width
1298
- screenMid = 0.5 * up.viewport.rootWidth()
1299
- if elementMid < screenMid
1300
- 'left'
1301
- else
1302
- 'right'
1303
-
1304
- ###**
1305
- Flattens the given `array` a single level deep.
1306
-
1307
- @function up.util.flatten
1308
- @param {Array} array
1309
- An array which might contain other arrays
1310
- @return {Array}
1311
- The flattened array
1312
- @experimental
1313
- ###
1314
- flatten = (array) ->
1315
- flattened = []
1316
- for object in array
1317
- if isList(object)
1318
- flattened.push(object...)
1319
- else
1320
- flattened.push(object)
1321
- flattened
1322
-
1323
- ###**
1324
- Maps each element using a mapping function,
1325
- then flattens the result into a new array.
1326
-
1327
- @function up.util.flatMap
1328
- @param {Array} array
1329
- @param {Function(element)} mapping
1330
- @return {Array}
1331
- @experimental
1332
- ###
1333
- flatMap = (array, block) ->
1334
- flatten map(array, block)
1335
-
1336
- ###**
1337
- Returns whether the given value is truthy.
1338
-
1339
- @function up.util.isTruthy
1340
- @internal
1341
- ###
1342
- isTruthy = (object) ->
1343
- !!object
1344
-
1345
- ###**
1346
- Sets the given callback as both fulfillment and rejection handler for the given promise.
1347
-
1348
- @function up.util.always
1349
- @internal
1350
- ###
1351
- always = (promise, callback) ->
1352
- promise.then(callback, callback)
1353
-
1354
- ###**
1355
- # Registers an empty rejection handler with the given promise.
1356
- # This prevents browsers from printing "Uncaught (in promise)" to the error
1357
- # console when the promise is rejection.
1358
- #
1359
- # This is helpful for event handlers where it is clear that no rejection
1360
- # handler will be registered:
1361
- #
1362
- # up.on('submit', 'form[up-target]', (event, $form) => {
1363
- # promise = up.submit($form)
1364
- # up.util.muteRejection(promise)
1365
- # })
1366
- #
1367
- # Does nothing if passed a missing value.
1368
- #
1369
- # @function up.util.muteRejection
1370
- # @param {Promise|undefined|null} promise
1371
- # @return {Promise}
1372
- ###
1373
- muteRejection = (promise) ->
1374
- promise?.catch(noop)
1375
-
1376
- ###**
1377
- @function up.util.newDeferred
1378
- @internal
1379
- ###
1380
- ###**
1381
- @function up.util.newDeferred
1382
- @internal
1383
- ###
1384
- newDeferred = ->
1385
- resolveFn = undefined
1386
- rejectFn = undefined
1387
- nativePromise = new Promise (givenResolve, givenReject) ->
1388
- resolveFn = givenResolve
1389
- rejectFn = givenReject
1390
- nativePromise.resolve = resolveFn
1391
- nativePromise.reject = rejectFn
1392
- nativePromise.promise = -> nativePromise # just return self
1393
- nativePromise
1394
-
1395
- ###**
1396
- Calls the given block. If the block throws an exception,
1397
- a rejected promise is returned instead.
1398
-
1399
- @function up.util.rejectOnError
1400
- @internal
1401
- ###
1402
- rejectOnError = (block) ->
1403
- try
1404
- block()
1405
- catch error
1406
- Promise.reject(error)
1407
-
1408
- sum = (list, block) ->
1409
- block = iteratee(block)
1410
- totalValue = 0
1411
- for entry in list
1412
- entryValue = block(entry)
1413
- if isGiven(entryValue) # ignore undefined/null, like SQL would do
1414
- totalValue += entryValue
1415
- totalValue
1416
-
1417
- isBasicObjectProperty = (k) ->
1418
- Object.prototype.hasOwnProperty(k)
1419
-
1420
- ###**
1421
- Returns whether the two arguments are equal by value.
1422
-
1423
- \#\#\# Comparison protocol
1424
-
1425
- - By default `up.util.isEqual()` can compare strings, numbers,
1426
- [array-like values](/up.util.isList), plain objects and `Date` objects.
1427
- - To make the copying protocol work with user-defined classes,
1428
- see `up.util.isEqual.key`.
1429
- - Objects without a defined comparison protocol are
1430
- defined by reference (`===`).
1431
-
1432
- @function up.util.isEqual
1433
- @param {any} a
1434
- @param {any} b
1435
- @return {boolean}
1436
- Whether the arguments are equal by value.
1437
- @experimental
1438
- ###
1439
- isEqual = (a, b) ->
1440
- a = a.valueOf() if a?.valueOf # Date, String objects, Number objects
1441
- b = b.valueOf() if b?.valueOf # Date, String objects, Number objects
1442
- if typeof(a) != typeof(b)
1443
- false
1444
- else if isList(a) && isList(b)
1445
- isEqualList(a, b)
1446
- else if isObject(a) && a[isEqual.key]
1447
- a[isEqual.key](b)
1448
- else if isOptions(a) && isOptions(b)
1449
- aKeys = Object.keys(a)
1450
- bKeys = Object.keys(b)
1451
- if isEqualList(aKeys, bKeys)
1452
- every aKeys, (aKey) -> isEqual(a[aKey], b[aKey])
1453
- else
1454
- false
1455
- else
1456
- a == b
1457
-
1458
- ###**
1459
- This property contains the name of a method that user-defined classes
1460
- may implement to hook into the `up.util.isEqual()` protocol.
1461
-
1462
- \#\#\# Example
1463
-
1464
- We have a user-defined `Account` class that we want to use with `up.util.isEqual()`:
1465
-
1466
- ```
1467
- class Account {
1468
- constructor(email) {
1469
- this.email = email
1470
- }
1471
-
1472
- [up.util.isEqual.key](other) {
1473
- return this.email === other.email;
1474
- }
1475
- }
1476
- ```
1477
-
1478
- Note that the protocol method is not actually named `'up.util.isEqual.key'`.
1479
- Instead it is named after the *value* of the `up.util.isEqual.key` property.
1480
- To do so, the code sample above is using a
1481
- [computed property name](https://medium.com/front-end-weekly/javascript-object-creation-356e504173a8)
1482
- in square brackets.
1483
-
1484
- We may now use `Account` instances with `up.util.isEqual()`:
1485
-
1486
- ```
1487
- one = new User('foo@foo.com')
1488
- two = new User('foo@foo.com')
1489
- three = new User('bar@bar.com')
1490
-
1491
- isEqual = up.util.isEqual(one, two)
1492
- // isEqual is now true
1493
-
1494
- isEqual = up.util.isEqual(one, three)
1495
- // isEqual is now false
1496
- ```
1497
-
1498
- @property up.util.isEqual.key
1499
- @param {string} key
1500
- @experimental
1501
- ###
1502
- isEqual.key = 'up.util.isEqual'
1503
-
1504
- isEqualList = (a, b) ->
1505
- a.length == b.length && every(a, (elem, index) -> isEqual(elem, b[index]))
1506
-
1507
- splitValues = (value, separator = ' ') ->
1508
- values = value.split(separator)
1509
- values = map values, (v) -> v.trim()
1510
- values = filterList(values, isPresent)
1511
- values
1512
-
1513
- endsWith = (string, search) ->
1514
- if search.length > string.length
1515
- false
1516
- else
1517
- string.substring(string.length - search.length) == search
1518
-
1519
- simpleEase = (x) ->
1520
- # easing: http://fooplot.com/?lang=de#W3sidHlwZSI6MCwiZXEiOiJ4PDAuNT8yKngqeDp4Kig0LXgqMiktMSIsImNvbG9yIjoiIzEzRjIxNyJ9LHsidHlwZSI6MCwiZXEiOiJzaW4oKHheMC43LTAuNSkqcGkpKjAuNSswLjUiLCJjb2xvciI6IiMxQTUyRUQifSx7InR5cGUiOjEwMDAsIndpbmRvdyI6WyItMS40NyIsIjEuNzgiLCItMC41NSIsIjEuNDUiXX1d
1521
- # easing nice: sin((x^0.7-0.5)*pi)*0.5+0.5
1522
- # easing performant: x < 0.5 ? 2*x*x : x*(4 - x*2)-1
1523
- # https://jsperf.com/easings/1
1524
- # Math.sin((Math.pow(x, 0.7) - 0.5) * Math.PI) * 0.5 + 0.5
1525
- if x < 0.5
1526
- 2*x*x
1527
- else
1528
- x*(4 - x*2)-1
1529
-
1530
- wrapValue = (object, constructor) ->
1531
- if object instanceof constructor
1532
- # This object has gone through instantiation and normalization before.
1533
- object
1534
- else
1535
- new constructor(object)
1536
-
1537
- # wrapArray = (objOrArray) ->
1538
- # if isUndefined(objOrArray)
1539
- # []
1540
- # else if isArray(objOrArray)
1541
- # objOrArray
1542
- # else
1543
- # [objOrArray]
1544
-
1545
- nextUid = 0
1546
-
1547
- uid = ->
1548
- nextUid++
1549
-
1550
- <% if ENV['JS_KNIFE'] %>knife: eval(Knife.point)<% end %>
1551
- parseUrl: parseUrl
1552
- normalizeUrl: normalizeUrl
1553
- normalizeMethod: normalizeMethod
1554
- methodAllowsPayload: methodAllowsPayload
1555
- # isGoodSelector: isGoodSelector
1556
- assign: assign
1557
- assignPolyfill: assignPolyfill
1558
- copy: copy
1559
- deepCopy: deepCopy
1560
- merge: merge
1561
- # deepAssign: deepAssign
1562
- # deepMerge: deepMerge
1563
- options: newOptions
1564
- fail: fail
1565
- each: each
1566
- eachIterator: eachIterator
1567
- map: map
1568
- flatMap: flatMap
1569
- mapObject: mapObject
1570
- times: times
1571
- findResult: findResult
1572
- some: some
1573
- any: ->
1574
- up.legacy.warn('up.util.any() has been renamed to up.util.some()')
1575
- some.apply(null, arguments)
1576
- every: every
1577
- all: ->
1578
- up.legacy.warn('up.util.all() has been renamed to up.util.every()')
1579
- every.apply(null, arguments)
1580
- detect: ->
1581
- up.legacy.warn('up.util.find() has been renamed to up.util.find()')
1582
- findInList.apply(null, arguments)
1583
- find: findInList
1584
- select: ->
1585
- up.legacy.warn('up.util.select() has been renamed to up.util.filter()')
1586
- filterList.apply(null, arguments)
1587
- filter: filterList
1588
- reject: reject
1589
- intersect: intersect
1590
- compact: compact
1591
- uniq: uniq
1592
- uniqBy: uniqBy
1593
- last: last
1594
- isNull: isNull
1595
- isDefined: isDefined
1596
- isUndefined: isUndefined
1597
- isGiven: isGiven
1598
- isMissing: isMissing
1599
- isPresent: isPresent
1600
- isBlank: isBlank
1601
- presence: presence
1602
- isObject: isObject
1603
- isFunction: isFunction
1604
- isString: isString
1605
- isBoolean: isBoolean
1606
- isNumber: isNumber
1607
- isElement: isElement
1608
- isJQuery: isJQuery
1609
- isPromise: isPromise
1610
- isOptions: isOptions
1611
- isArray: isArray
1612
- isFormData: isFormData
1613
- isNodeList: isNodeList
1614
- isArguments: isArguments
1615
- isList: isList
1616
- isUnmodifiedKeyEvent: isUnmodifiedKeyEvent
1617
- isUnmodifiedMouseEvent: isUnmodifiedMouseEvent
1618
- timer: scheduleTimer
1619
- setTimer: ->
1620
- up.legacy.warn('up.util.setTimer() has been renamed to up.util.timer()')
1621
- scheduleTimer.apply(null, arguments)
1622
- escapePressed: escapePressed
1623
- contains: contains
1624
- toArray: toArray
1625
- only: only
1626
- except: except
1627
- # pickBy: pickBy
1628
- unresolvablePromise: unresolvablePromise
1629
- remove: remove
1630
- memoize: memoize
1631
- error: fail
1632
- pluckKey: pluckKey
1633
- renameKey: renameKey
1634
- extractOptions: extractOptions
1635
- extractCallback: extractCallback
1636
- noop: noop
1637
- asyncNoop: asyncNoop
1638
- identity: identity
1639
- escapeHtml: escapeHtml
1640
- escapeRegexp: escapeRegexp
1641
- sequence: sequence
1642
- previewable: previewable
1643
- # parsePath: parsePath
1644
- evalOption: evalOption
1645
- horizontalScreenHalf: horizontalScreenHalf
1646
- flatten: flatten
1647
- isTruthy: isTruthy
1648
- newDeferred: newDeferred
1649
- always: always
1650
- muteRejection: muteRejection
1651
- rejectOnError: rejectOnError
1652
- isBasicObjectProperty: isBasicObjectProperty
1653
- isCrossDomain: isCrossDomain
1654
- selectorForElement: ->
1655
- up.legacy.warn('up.util.selectorForElement() has been renamed to up.element.toSelector()')
1656
- up.element.toSelector.apply(null, arguments)
1657
- nextFrame: ->
1658
- up.legacy.warn('up.util.nextFrame() has been renamed to up.util.task()')
1659
- queueTask.apply(null, arguments)
1660
- task: queueTask
1661
- microtask: queueMicrotask
1662
- isEqual: isEqual
1663
- splitValues : splitValues
1664
- endsWith: endsWith
1665
- sum: sum
1666
- # wrapArray: wrapArray
1667
- wrapList: wrapList
1668
- wrapValue: wrapValue
1669
- simpleEase: simpleEase
1670
- values: objectValues
1671
- partial: partial
1672
- arrayToSet: arrayToSet
1673
- setToArray: setToArray
1674
- uid: uid
1675
-
1676
- up.fail = up.util.fail