unpoly-rails 0.62.1 → 2.0.0.pre.rc6

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 +60 -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 +1225 -0
  19. data/dist/unpoly-migrate.min.js +1 -0
  20. data/dist/unpoly.css +109 -140
  21. data/dist/unpoly.js +15805 -10558
  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 +55 -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 -45
  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 -544
  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 -1075
  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 -827
  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 -476
  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 -2624
  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 -939
  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,401 +0,0 @@
1
- u = up.util
2
- $ = jQuery
3
-
4
- describe 'up.feedback', ->
5
-
6
- beforeEach ->
7
- up.history.config.enabled = true
8
- up.modal.config.openAnimation = 'none'
9
- up.modal.config.closeAnimation = 'none'
10
- up.popup.config.openAnimation = 'none'
11
- up.popup.config.closeAnimation = 'none'
12
-
13
- describe 'unobtrusive behavior', ->
14
-
15
- describe '[up-nav]', ->
16
-
17
- it 'marks a child link as .up-current if it links to the current URL', ->
18
- up.history.replace('/foo')
19
- $nav = $fixture('div[up-nav]')
20
- $currentLink = $nav.affix('a[href="/foo"]')
21
- $otherLink = $nav.affix('a[href="/bar"]')
22
- up.hello($nav)
23
- expect($currentLink).toHaveClass('up-current')
24
- expect($otherLink).not.toHaveClass('up-current')
25
-
26
- it 'marks the element as .up-current if it is also a link to the current URL', ->
27
- up.history.replace('/foo')
28
- $currentLink = $fixture('a[href="/foo"][up-nav]')
29
- $otherLink = $fixture('a[href="/bar"][up-nav]')
30
- up.hello($currentLink)
31
- up.hello($otherLink)
32
- expect($currentLink).toHaveClass('up-current')
33
- expect($otherLink).not.toHaveClass('up-current')
34
-
35
- it 'does not mark a link as .up-current if the link is outside an [up-nav]', ->
36
- up.history.replace('/foo')
37
- $nav = $fixture('div[up-nav]')
38
- $currentLinkInNav = $nav.affix('a[href="/foo"]')
39
- $currentLinkOutsideNav = $fixture('a[href="/foo"]')
40
- up.hello($nav)
41
- expect($currentLinkInNav).toHaveClass('up-current')
42
- expect($currentLinkOutsideNav).not.toHaveClass('up-current')
43
-
44
- it 'marks a replaced child link as .up-current if it links to the current URL', asyncSpec (next) ->
45
- up.history.replace('/foo')
46
- $nav = $fixture('div[up-nav]')
47
- $nav.affix('a.link[href="/bar"]').text('old link')
48
- up.hello($nav)
49
-
50
- expect('.link').toHaveText('old link')
51
- expect('.link').not.toHaveClass('up-current')
52
-
53
- up.replace('.link', '/src', history: false)
54
-
55
- next =>
56
- @respondWith """
57
- <a class="link" href="/foo">
58
- new link
59
- </a>
60
- """
61
-
62
- next =>
63
- expect('.link').toHaveText('new link')
64
- expect('.link').toHaveClass('up-current')
65
-
66
- it 'marks any link as .up-current if its up-href attribute matches the current URL', ->
67
- up.history.replace('/foo')
68
- $nav = $fixture('div[up-nav]')
69
- $currentLink = $nav.affix('span[up-href="/foo"]')
70
- $otherLink = $nav.affix('span[up-href="/bar"]')
71
- up.hello($nav)
72
- expect($currentLink).toHaveClass('up-current')
73
- expect($otherLink).not.toHaveClass('up-current')
74
-
75
- it 'matches the current and destination URLs if they only differ by a trailing slash', ->
76
- up.history.replace('/foo')
77
- $nav = $fixture('div[up-nav]')
78
- $currentLink = $nav.affix('span[up-href="/foo/"]')
79
- up.hello($nav)
80
- expect($currentLink).toHaveClass('up-current')
81
-
82
- it 'does not match the current and destination URLs if they differ in the search', ->
83
- up.history.replace('/foo?q=1')
84
- $nav = $fixture('div[up-nav]')
85
- $currentLink = $nav.affix('span[up-href="/foo?q=2"]')
86
- up.hello($nav)
87
- expect($currentLink).not.toHaveClass('up-current')
88
-
89
- it 'marks any link as .up-current if any of its space-separated up-alias values matches the current URL', ->
90
- up.history.replace('/foo')
91
- $nav = $fixture('div[up-nav]')
92
- $currentLink = $nav.affix('a[href="/x"][up-alias="/aaa /foo /bbb"]')
93
- $otherLink = $nav.affix('a[href="/y"][up-alias="/bar"]')
94
- up.hello($nav)
95
- expect($currentLink).toHaveClass('up-current')
96
- expect($otherLink).not.toHaveClass('up-current')
97
-
98
- it 'does not throw if the current location does not match an up-alias wildcard (bugfix)', ->
99
- inserter = -> up.hello(fixture('a[up-nav][up-alias="/qqqq*"]'))
100
- expect(inserter).not.toThrow()
101
-
102
- it 'does not highlight a link to "#" (commonly used for JS-only buttons)', ->
103
- $nav = $fixture('div[up-nav]')
104
- $link = $nav.affix('a[href="#"]')
105
- up.hello($nav)
106
- expect($link).not.toHaveClass('up-current')
107
-
108
- it 'does not highlight links with unsafe methods', ->
109
- up.history.replace('/foo')
110
- $nav = $fixture('div[up-nav]')
111
- $defaultLink = $nav.affix('a[href="/foo"]')
112
- $getLink = $nav.affix('a[href="/foo"][up-method="get"]')
113
- $putLink = $nav.affix('a[href="/foo"][up-method="put"]')
114
- $patchLink = $nav.affix('a[href="/foo"][up-method="patch"]')
115
- $postLink = $nav.affix('a[href="/foo"][up-method="post"]')
116
- $deleteLink = $nav.affix('a[href="/foo"][up-method="delete"]')
117
- up.hello($nav)
118
-
119
- expect($defaultLink).toHaveClass('up-current')
120
- expect($getLink).toHaveClass('up-current')
121
- expect($putLink).not.toHaveClass('up-current')
122
- expect($patchLink).not.toHaveClass('up-current')
123
- expect($postLink).not.toHaveClass('up-current')
124
- expect($deleteLink).not.toHaveClass('up-current')
125
-
126
- it 'marks URL prefixes as .up-current if an up-alias value ends in *', ->
127
- up.history.replace('/foo/123')
128
-
129
- $nav = $fixture('div[up-nav]')
130
- $currentLink = $nav.affix('a[href="/x"][up-alias="/aaa /foo/* /bbb"]')
131
- $otherLink = $nav.affix('a[href="/y"][up-alias="/bar"]')
132
- up.hello($nav)
133
-
134
- expect($currentLink).toHaveClass('up-current')
135
- expect($otherLink).not.toHaveClass('up-current')
136
-
137
- it 'marks URL prefixes as .up-current if an up-alias has multiple * placeholders', ->
138
- up.history.replace('/a-foo-b-bar-c')
139
-
140
- $nav = $fixture('div[up-nav]')
141
- $currentLink = $nav.affix('a[href="/x"][up-alias="*-foo-*-bar-*"]')
142
- $otherLink1 = $nav.affix('a[href="/y"][up-alias="/foo-bar"]')
143
- $otherLink2 = $nav.affix('a[href="/y"][up-alias="/foo-b-bar"]')
144
- $otherLink3 = $nav.affix('a[href="/y"][up-alias="/a-foo-b-bar"]')
145
- $otherLink4 = $nav.affix('a[href="/y"][up-alias="/foo-b-bar-c"]')
146
- $otherLink5 = $nav.affix('a[href="/y"][up-alias="/a-foo-b-bar-c-d"]')
147
- up.hello($nav)
148
-
149
- expect($currentLink).toHaveClass('up-current')
150
- expect($otherLink1).not.toHaveClass('up-current')
151
- expect($otherLink2).not.toHaveClass('up-current')
152
- expect($otherLink3).not.toHaveClass('up-current')
153
- expect($otherLink4).not.toHaveClass('up-current')
154
- expect($otherLink5).not.toHaveClass('up-current')
155
-
156
-
157
- it 'allows to configure a custom "current" class in addition to .up-current', ->
158
- up.feedback.config.currentClasses.push('highlight')
159
- up.history.replace('/foo')
160
- $nav = $fixture('div[up-nav]')
161
- $currentLink = $nav.affix('a[href="/foo"]')
162
- up.hello($nav)
163
-
164
- expect($currentLink).toHaveClass('highlight')
165
- expect($currentLink).toHaveClass('up-current')
166
-
167
- it 'allows to configure multiple additional "current" classes', ->
168
- up.feedback.config.currentClasses.push('highlight1')
169
- up.feedback.config.currentClasses.push('highlight2')
170
- up.history.replace('/foo')
171
- $nav = $fixture('div[up-nav]')
172
- $currentLink = $nav.affix('a[href="/foo"]')
173
- up.hello($nav)
174
-
175
- expect($currentLink).toHaveClass('highlight1')
176
- expect($currentLink).toHaveClass('highlight2')
177
- expect($currentLink).toHaveClass('up-current')
178
-
179
- it 'allows to configure additional nav selectors', ->
180
- up.history.replace('/foo')
181
- up.feedback.config.navs.push('.navi')
182
- $nav = $fixture('div.navi')
183
- $currentLink = $nav.affix('a[href="/foo"]')
184
- $otherLink = $nav.affix('a[href="/bar"]')
185
- up.hello($nav)
186
- expect($currentLink).toHaveClass('up-current')
187
- expect($otherLink).not.toHaveClass('up-current')
188
-
189
- describeCapability 'canPushState', ->
190
-
191
- describe 'updating .up-current marks wen the URL changes', ->
192
-
193
- it 'marks a link as .up-current if it links to the current URL, but is missing a trailing slash', asyncSpec (next) ->
194
- $nav = $fixture('div[up-nav]')
195
- $link = $nav.affix('a[href="/foo"][up-target=".main"]')
196
- up.hello($nav)
197
-
198
- fixture('.main')
199
- Trigger.clickSequence($link)
200
-
201
- next =>
202
- @respondWith
203
- responseHeaders: { 'X-Up-Location': '/foo/' }
204
- responseText: '<div class="main">new-text</div>'
205
-
206
- next =>
207
- expect($link).toHaveClass('up-current')
208
-
209
- it 'marks a link as .up-current if it links to the current URL, but has an extra trailing slash', asyncSpec (next) ->
210
- $nav = $fixture('div[up-nav]')
211
- $link = $nav.affix('a[href="/foo/"][up-target=".main"]')
212
- up.hello($nav)
213
-
214
- fixture('.main')
215
- Trigger.clickSequence($link)
216
-
217
- next =>
218
- @respondWith
219
- responseHeaders: { 'X-Up-Location': '/foo' }
220
- responseText: '<div class="main">new-text</div>'
221
-
222
- next =>
223
- expect($link).toHaveClass('up-current')
224
-
225
- it 'marks a link as .up-current if it links to an URL currently shown either within or below the modal', asyncSpec (next) ->
226
- up.history.replace('/foo')
227
-
228
- $nav = $fixture('div[up-nav]')
229
- $backgroundLink = $nav.affix('a[href="/foo"]')
230
- $modalLink = $nav.affix('a[href="/bar"][up-modal=".main"]')
231
- $unrelatedLink = $nav.affix('a[href="/baz"]')
232
- up.hello($nav)
233
-
234
- Trigger.clickSequence($modalLink)
235
-
236
- next =>
237
- @respondWith('<div class="main">new-text</div>')
238
-
239
- next =>
240
- expect($backgroundLink).toHaveClass('up-current')
241
- expect($modalLink).toHaveClass('up-current')
242
- expect($unrelatedLink).not.toHaveClass('up-current')
243
- next.await up.modal.close()
244
-
245
- next =>
246
- expect($backgroundLink).toHaveClass('up-current')
247
- expect($modalLink).not.toHaveClass('up-current')
248
- expect($unrelatedLink).not.toHaveClass('up-current')
249
-
250
- it "marks a link as .up-current if it links to the URL currently either within or below the popup, even if the popup doesn't change history", asyncSpec (next) ->
251
- up.history.replace('/foo')
252
-
253
- # This is actually the default. Popups don't change the address bar by default,
254
- # but we still want to cause their URL to mark links as current.
255
- up.popup.config.history = false
256
-
257
- $nav = $fixture('div[up-nav]')
258
- $backgroundLink = $nav.affix('a[href="/foo"]')
259
- $popupLink = $nav.affix('a[href="/bar"][up-popup=".main"]')
260
- $unrelatedLink = $nav.affix('a[href="/baz"]')
261
- up.hello($nav)
262
-
263
- expect(up.browser.url()).toMatchUrl('/foo')
264
- expect(up.popup.coveredUrl()).toBeMissing()
265
-
266
- next =>
267
- Trigger.clickSequence($popupLink)
268
-
269
- next =>
270
- @respondWith('<div class="main">new-text</div>')
271
-
272
- next =>
273
- expect(up.browser.url()).toMatchUrl('/foo') # popup did not change history
274
- expect(up.popup.url()).toMatchUrl('/bar') # popup still knows which URL it is displaying
275
- expect($backgroundLink).toHaveClass('up-current')
276
- expect($popupLink).toHaveClass('up-current')
277
- expect($unrelatedLink).not.toHaveClass('up-current')
278
-
279
- next.await up.popup.close()
280
-
281
- next =>
282
- expect($backgroundLink).toHaveClass('up-current')
283
- expect($popupLink).not.toHaveClass('up-current')
284
- expect($unrelatedLink).not.toHaveClass('up-current')
285
-
286
- it "respects links that are added to an existing [up-nav] by a fragment update", asyncSpec (next) ->
287
- $nav = $fixture('.nav[up-nav]')
288
- $link = $nav.affix('a[href="/foo"][up-target=".main"]')
289
- $more = $nav.affix('.more')
290
- up.hello($nav)
291
-
292
- up.extract '.more', '<div class="more"><a href="/bar"></div>', history: '/bar'
293
-
294
- next =>
295
- $moreLink = $('.more').find('a')
296
- expect($moreLink).toBeAttached()
297
- expect($moreLink).toHaveClass('up-current')
298
-
299
-
300
- describe '.up-active', ->
301
-
302
- describeCapability 'canPushState', ->
303
-
304
- it 'marks clicked links as .up-active until the request finishes', asyncSpec (next) ->
305
- $link = $fixture('a[href="/foo"][up-target=".main"]')
306
- fixture('.main')
307
- Trigger.clickSequence($link)
308
-
309
- next =>
310
- expect($link).toHaveClass('up-active')
311
- @respondWith('<div class="main">new-text</div>')
312
-
313
- next =>
314
- expect($link).not.toHaveClass('up-active')
315
-
316
- it 'does not mark a link as .up-active while it is preloading', asyncSpec (next) ->
317
- $link = $fixture('a[href="/foo"][up-target=".main"]')
318
- fixture('.main')
319
-
320
- up.proxy.preload($link)
321
-
322
- next =>
323
- expect(jasmine.Ajax.requests.count()).toEqual(1)
324
- expect($link).not.toHaveClass('up-active')
325
-
326
- it 'marks links with [up-instant] on mousedown as .up-active until the request finishes', asyncSpec (next) ->
327
- $link = $fixture('a[href="/foo"][up-instant][up-target=".main"]')
328
- fixture('.main')
329
- Trigger.mousedown($link)
330
-
331
- next => expect($link).toHaveClass('up-active')
332
- next => @respondWith('<div class="main">new-text</div>')
333
- next => expect($link).not.toHaveClass('up-active')
334
-
335
- it 'prefers to mark an enclosing [up-expand] click area', asyncSpec (next) ->
336
- $area = $fixture('div[up-expand] a[href="/foo"][up-target=".main"]')
337
- up.hello($area)
338
- $link = $area.find('a')
339
- fixture('.main')
340
- Trigger.clickSequence($link)
341
-
342
- next =>
343
- expect($link).not.toHaveClass('up-active')
344
- expect($area).toHaveClass('up-active')
345
- next =>
346
- @respondWith('<div class="main">new-text</div>')
347
- next =>
348
- expect($area).not.toHaveClass('up-active')
349
-
350
- it 'removes .up-active when a link with [up-confirm] was not confirmed', asyncSpec (next) ->
351
- $link = $fixture('a[href="/foo"][up-modal=".main"][up-confirm="Really follow?"]')
352
- spyOn(up.browser, 'whenConfirmed').and.returnValue(Promise.reject('User aborted'))
353
-
354
- Trigger.clickSequence($link)
355
-
356
- next =>
357
- expect($link).not.toHaveClass('up-active')
358
-
359
- it 'marks clicked modal openers as .up-active while the modal is loading', asyncSpec (next) ->
360
- $link = $fixture('a[href="/foo"][up-modal=".main"]')
361
- fixture('.main')
362
- Trigger.clickSequence($link)
363
-
364
- next => expect($link).toHaveClass('up-active')
365
- next => @respondWith('<div class="main">new-text</div>')
366
- next => expect($link).not.toHaveClass('up-active')
367
-
368
- it 'removes .up-active from a clicked modal opener if the target is already preloaded (bugfix)', asyncSpec (next) ->
369
- $link = $fixture('a[href="/foo"][up-modal=".main"]')
370
- up.proxy.preload($link)
371
-
372
- next => @respondWith('<div class="main">new-text</div>')
373
- next => Trigger.clickSequence($link)
374
- next =>
375
- expect('.up-modal .main').toHaveText('new-text')
376
- expect($link).not.toHaveClass('up-active')
377
-
378
- it 'removes .up-active from a clicked link if the target is already preloaded (bugfix)', asyncSpec (next) ->
379
- $link = $fixture('a[href="/foo"][up-target=".main"]')
380
- fixture('.main')
381
- up.proxy.preload($link)
382
-
383
- next => @respondWith('<div class="main">new-text</div>')
384
- next => Trigger.clickSequence($link)
385
- next =>
386
- expect('.main').toHaveText('new-text')
387
- expect($link).not.toHaveClass('up-active')
388
-
389
- it 'removes .up-active from a clicked link if the request fails (bugfix)', asyncSpec (next) ->
390
- $link = $fixture('a[href="/foo"][up-target=".main"]')
391
- fixture('.main')
392
- Trigger.clickSequence($link)
393
-
394
- next =>
395
- expect($link).toHaveClass('up-active')
396
- # @respondWith
397
- # responseText: '<div class="main">failed</div>'
398
- # status: 400
399
- #
400
- # next =>
401
- # expect($link).not.toHaveClass('up-active')
@@ -1,1527 +0,0 @@
1
- u = up.util
2
- e = up.element
3
- $ = jQuery
4
-
5
- describe 'up.form', ->
6
-
7
- describe 'JavaScript functions', ->
8
-
9
- describe 'up.form.fields', ->
10
-
11
- it 'returns a list of form fields within the given element', ->
12
- form = fixture('form')
13
- textField = e.affix(form, 'input[type=text]')
14
- select = e.affix(form, 'select')
15
- results = up.form.fields(form)
16
- expect(results).toMatchList([textField, select])
17
-
18
- it 'returns an empty list if the given element contains no form fields', ->
19
- form = fixture('form')
20
- results = up.form.fields(form)
21
- expect(results).toMatchList([])
22
-
23
- it 'returns a list of the given element if the element is itself a form field', ->
24
- textArea = fixture('textarea')
25
- results = up.form.fields(textArea)
26
- expect(results).toMatchList([textArea])
27
-
28
- it 'ignores fields outside the given form', ->
29
- form1 = fixture('form')
30
- form1Field = e.affix(form1, 'input[type=text]')
31
- form2 = fixture('form')
32
- form2Field = e.affix(form2, 'input[type=text]')
33
- results = up.form.fields(form1)
34
- expect(results).toMatchList([form1Field])
35
-
36
- it "includes fields outside the form with a [form] attribute matching the given form's ID", ->
37
- form = fixture('form#form-id')
38
- insideField = e.affix(form, 'input[type=text]')
39
- outsideField = fixture('input[type=text][form=form-id]')
40
- results = up.form.fields(form)
41
- expect(results).toMatchList([insideField, outsideField])
42
-
43
- it "does not return duplicate fields if a field with a matching [form] attribute is also a child of the form", ->
44
- form = fixture('form#form-id')
45
- field = e.affix(form, 'input[type=text][form=form-id]')
46
- results = up.form.fields(form)
47
- expect(results).toMatchList([field])
48
-
49
-
50
- describe 'up.observe', ->
51
-
52
- beforeEach ->
53
- up.form.config.observeDelay = 0
54
-
55
- # Actually we only need `input`, but we want to notice
56
- # if another script manually triggers `change` on the element.
57
- changeEvents = ['input', 'change']
58
-
59
- describe 'when the first argument is a form field', ->
60
-
61
- u.each changeEvents, (eventName) ->
62
-
63
- describe "when the input receives a #{eventName} event", ->
64
-
65
- it "runs the callback if the value changed", asyncSpec (next) ->
66
- $input = $fixture('input[name="input-name"][value="old-value"]')
67
- callback = jasmine.createSpy('change callback')
68
- up.observe($input, callback)
69
- $input.val('new-value')
70
- u.times 2, -> Trigger[eventName]($input)
71
- next =>
72
- expect(callback).toHaveBeenCalledWith('new-value', 'input-name')
73
- expect(callback.calls.count()).toEqual(1)
74
-
75
- it "does not run the callback if the value didn't change", asyncSpec (next) ->
76
- $input = $fixture('input[name="input-name"][value="old-value"]')
77
- callback = jasmine.createSpy('change callback')
78
- up.observe($input, callback)
79
- Trigger[eventName]($input)
80
- next =>
81
- expect(callback).not.toHaveBeenCalled()
82
-
83
- it 'debounces the callback when the { delay } option is given', asyncSpec (next) ->
84
- $input = $fixture('input[name="input-name"][value="old-value"]')
85
- callback = jasmine.createSpy('change callback')
86
- up.observe($input, { delay: 200 }, callback)
87
- $input.val('new-value-1')
88
- Trigger[eventName]($input)
89
-
90
- next.after 100, ->
91
- # 100 ms after change 1: We're still waiting for the 200ms delay to expire
92
- expect(callback.calls.count()).toEqual(0)
93
-
94
- next.after 200, ->
95
- # 300 ms after change 1: The 200ms delay has expired
96
- expect(callback.calls.count()).toEqual(1)
97
- expect(callback.calls.mostRecent().args[0]).toEqual('new-value-1')
98
- $input.val('new-value-2')
99
- Trigger[eventName]($input)
100
-
101
- next.after 80, ->
102
- # 80 ms after change 2: We change again, resetting the delay
103
- expect(callback.calls.count()).toEqual(1)
104
- $input.val('new-value-3')
105
- Trigger[eventName]($input)
106
-
107
- next.after 170, ->
108
- # 250 ms after change 2, which was superseded by change 3
109
- # 170 ms after change 3
110
- expect(callback.calls.count()).toEqual(1)
111
-
112
- next.after 130, ->
113
- # 190 ms after change 2, which was superseded by change 3
114
- # 150 ms after change 3
115
- expect(callback.calls.count()).toEqual(2)
116
- expect(callback.calls.mostRecent().args[0]).toEqual('new-value-3')
117
-
118
- it 'delays a callback if a previous async callback is taking long to execute', asyncSpec (next) ->
119
- $input = $fixture('input[name="input-name"][value="old-value"]')
120
- callbackCount = 0
121
- callback = ->
122
- callbackCount += 1
123
- return up.specUtil.promiseTimer(100)
124
- up.observe($input, { delay: 1 }, callback)
125
- $input.val('new-value-1')
126
- Trigger[eventName]($input)
127
-
128
- next.after 30, ->
129
- # Callback has been called and takes 100 ms to complete
130
- expect(callbackCount).toEqual(1)
131
- $input.val('new-value-2')
132
- Trigger[eventName]($input)
133
-
134
- next.after 30, ->
135
- # Second callback is triggerd, but waits for first callback to complete
136
- expect(callbackCount).toEqual(1)
137
-
138
- next.after 90, ->
139
- # After 150 ms the first callback should be finished and the queued 2nd callback has executed
140
- expect(callbackCount).toEqual(2)
141
-
142
- it 'only runs the last callback when a previous long-running callback has been delaying multiple callbacks', asyncSpec (next) ->
143
- $input = $fixture('input[name="input-name"][value="old-value"]')
144
-
145
- callbackArgs = []
146
- callback = (value, field) ->
147
- callbackArgs.push(value)
148
- return up.specUtil.promiseTimer(100)
149
-
150
- up.observe($input, { delay: 1 }, callback)
151
- $input.val('new-value-1')
152
- Trigger[eventName]($input)
153
-
154
- next.after 10, ->
155
- # Callback has been called and takes 100 ms to complete
156
- expect(callbackArgs).toEqual ['new-value-1']
157
- $input.val('new-value-2')
158
- Trigger[eventName]($input)
159
-
160
- next.after 10, ->
161
- expect(callbackArgs).toEqual ['new-value-1']
162
- $input.val('new-value-3')
163
- Trigger[eventName]($input)
164
-
165
- next.after 100, ->
166
- expect(callbackArgs).toEqual ['new-value-1', 'new-value-3']
167
-
168
- describe 'when the first argument is a checkbox', ->
169
-
170
- it 'runs the callback when the checkbox changes its checked state', asyncSpec (next) ->
171
- $form = $fixture('form')
172
- $checkbox = $form.affix('input[name="input-name"][type="checkbox"][value="checkbox-value"]')
173
- callback = jasmine.createSpy('change callback')
174
- up.observe($checkbox, callback)
175
- expect($checkbox.is(':checked')).toBe(false)
176
- Trigger.clickSequence($checkbox)
177
-
178
- next =>
179
- expect($checkbox.is(':checked')).toBe(true)
180
- expect(callback.calls.count()).toEqual(1)
181
- Trigger.clickSequence($checkbox)
182
-
183
- next =>
184
- expect($checkbox.is(':checked')).toBe(false)
185
- expect(callback.calls.count()).toEqual(2)
186
-
187
- it 'runs the callback when the checkbox is toggled by clicking its label', asyncSpec (next) ->
188
- $form = $fixture('form')
189
- $checkbox = $form.affix('input#tick[name="input-name"][type="checkbox"][value="checkbox-value"]')
190
- $label = $form.affix('label[for="tick"]').text('tick label')
191
- callback = jasmine.createSpy('change callback')
192
- up.observe($checkbox, callback)
193
- expect($checkbox.is(':checked')).toBe(false)
194
- Trigger.clickSequence($label)
195
-
196
- next =>
197
- expect($checkbox.is(':checked')).toBe(true)
198
- expect(callback.calls.count()).toEqual(1)
199
- Trigger.clickSequence($label)
200
-
201
- next =>
202
- expect($checkbox.is(':checked')).toBe(false)
203
- expect(callback.calls.count()).toEqual(2)
204
-
205
- describe 'when the first argument is a radio button group', ->
206
-
207
- it 'runs the callback when the group changes its selection', asyncSpec (next) ->
208
- $form = $fixture('form')
209
- $radio1 = $form.affix('input[type="radio"][name="group"][value="1"]')
210
- $radio2 = $form.affix('input[type="radio"][name="group"][value="2"]')
211
- $group = $radio1.add($radio2)
212
- callback = jasmine.createSpy('change callback')
213
- up.observe($group, callback)
214
- expect($radio1.is(':checked')).toBe(false)
215
-
216
- Trigger.clickSequence($radio1)
217
-
218
- next =>
219
- expect($radio1.is(':checked')).toBe(true)
220
- expect(callback.calls.count()).toEqual(1)
221
- # Trigger.clickSequence($radio2)
222
- $radio1[0].checked = false
223
- $radio2[0].checked = true
224
- Trigger.change($radio2)
225
-
226
- next =>
227
- expect($radio1.is(':checked')).toBe(false)
228
- expect(callback.calls.count()).toEqual(2)
229
-
230
- it "runs the callbacks when a radio button is selected or deselected by clicking a label in the group", asyncSpec (next) ->
231
- $form = $fixture('form')
232
- $radio1 = $form.affix('input#radio1[type="radio"][name="group"][value="1"]')
233
- $radio1Label = $form.affix('label[for="radio1"]').text('label 1')
234
- $radio2 = $form.affix('input#radio2[type="radio"][name="group"][value="2"]')
235
- $radio2Label = $form.affix('label[for="radio2"]').text('label 2')
236
- $group = $radio1.add($radio2)
237
- callback = jasmine.createSpy('change callback')
238
- up.observe($group, callback)
239
- expect($radio1.is(':checked')).toBe(false)
240
- Trigger.clickSequence($radio1Label)
241
-
242
- next =>
243
- expect($radio1.is(':checked')).toBe(true)
244
- expect(callback.calls.count()).toEqual(1)
245
- Trigger.clickSequence($radio2Label)
246
-
247
- next =>
248
- expect($radio1.is(':checked')).toBe(false)
249
- expect(callback.calls.count()).toEqual(2)
250
-
251
- it "takes the group's initial selected value into account", asyncSpec (next) ->
252
- $form = $fixture('form')
253
- $radio1 = $form.affix('input[type="radio"][name="group"][value="1"][checked="checked"]')
254
- $radio2 = $form.affix('input[type="radio"][name="group"][value="2"]')
255
- $group = $radio1.add($radio2)
256
- callback = jasmine.createSpy('change callback')
257
- up.observe($group, callback)
258
- expect($radio1.is(':checked')).toBe(true)
259
- expect($radio2.is(':checked')).toBe(false)
260
- Trigger.clickSequence($radio1)
261
-
262
- next =>
263
- # Since the radio button was already checked, the click doesn't do anything
264
- expect($radio1.is(':checked')).toBe(true)
265
- expect($radio2.is(':checked')).toBe(false)
266
- # Since the radio button was already checked, clicking it again won't trigger the callback
267
- expect(callback.calls.count()).toEqual(0)
268
- Trigger.clickSequence($radio2)
269
-
270
- next =>
271
- expect($radio1.is(':checked')).toBe(false)
272
- expect($radio2.is(':checked')).toBe(true)
273
- expect(callback.calls.count()).toEqual(1)
274
-
275
- describe 'when the first argument is a form', ->
276
-
277
- u.each changeEvents, (eventName) ->
278
-
279
- describe "when any of the form's inputs receives a #{eventName} event", ->
280
-
281
- it "runs the callback if the value changed", asyncSpec (next) ->
282
- $form = $fixture('form')
283
- $input = $form.affix('input[name="input-name"][value="old-value"]')
284
- callback = jasmine.createSpy('change callback')
285
- up.observe($form, callback)
286
- $input.val('new-value')
287
- u.times 2, -> Trigger[eventName]($input)
288
- next =>
289
- expect(callback).toHaveBeenCalledWith('new-value', 'input-name')
290
- expect(callback.calls.count()).toEqual(1)
291
-
292
- it "does not run the callback if the value didn't change", asyncSpec (next) ->
293
- $form = $fixture('form')
294
- $input = $form.affix('input[name="input-name"][value="old-value"]')
295
- callback = jasmine.createSpy('change callback')
296
- up.observe($form, callback)
297
- Trigger[eventName]($input)
298
- next =>
299
- expect(callback).not.toHaveBeenCalled()
300
-
301
- # it 'runs the callback only once when a radio button group changes its selection', ->
302
- # $form = $fixture('form')
303
- # $radio1 = $form.affix('input[type="radio"][name="group"][value="1"][checked="checked"]')
304
- # $radio2 = $form.affix('input[type="radio"][name="group"][value="2"]')
305
- # callback = jasmine.createSpy('change callback')
306
- # up.observe($form, callback)
307
- # $radio2.get(0).click()
308
- # u.task ->
309
- # expect(callback.calls.count()).toEqual(1)
310
-
311
-
312
- describe 'with { batch: true } options', ->
313
-
314
- it 'calls the callback once with all collected changes in a diff object', asyncSpec (next) ->
315
- $form = $fixture('form')
316
- $input1 = $form.affix('input[name="input1"][value="input1-a"]')
317
- $input2 = $form.affix('input[name="input2"][value="input2-a"]')
318
- callback = jasmine.createSpy('change callback')
319
- up.observe($form, { batch: true }, callback)
320
-
321
- next ->
322
- expect(callback.calls.count()).toEqual(0)
323
-
324
- $input1.val('input1-b')
325
- Trigger.change($input1)
326
- $input2.val('input2-b')
327
- Trigger.change($input2)
328
-
329
- next ->
330
- expect(callback.calls.count()).toEqual(1)
331
- expect(callback.calls.mostRecent().args[0]).toEqual {
332
- 'input1': 'input1-b'
333
- 'input2': 'input2-b'
334
- }
335
-
336
- $input2.val('input2-c')
337
- Trigger.change($input2)
338
-
339
- next ->
340
- expect(callback.calls.count()).toEqual(2)
341
- expect(callback.calls.mostRecent().args[0]).toEqual {
342
- 'input2': 'input2-c'
343
- }
344
-
345
-
346
- describe 'up.submit', ->
347
-
348
- it 'emits a preventable up:form:submit event', asyncSpec (next) ->
349
- $form = $fixture('form[action="/form-target"][up-target=".response"]')
350
-
351
- listener = jasmine.createSpy('submit listener').and.callFake (event) ->
352
- event.preventDefault()
353
-
354
- $form.on('up:form:submit', listener)
355
-
356
- up.submit($form)
357
-
358
- next =>
359
- expect(listener).toHaveBeenCalled()
360
- element = listener.calls.mostRecent().args[1]
361
- expect(element).toEqual(element)
362
-
363
- # No request should be made because we prevented the event
364
- expect(jasmine.Ajax.requests.count()).toEqual(0)
365
-
366
- describeCapability 'canPushState', ->
367
-
368
- beforeEach ->
369
- up.history.config.enabled = true
370
- @$form = $fixture('form[action="/form-target"][method="put"][up-target=".response"]')
371
- @$form.append('<input name="field1" value="value1">')
372
- @$form.append('<input name="field2" value="value2">')
373
- $fixture('.response').text('old-text')
374
-
375
- it 'submits the given form and replaces the target with the response', asyncSpec (next) ->
376
- up.submit(@$form)
377
-
378
- next =>
379
- expect(@lastRequest().url).toMatchUrl('/form-target')
380
- expect(@lastRequest()).toHaveRequestMethod('PUT')
381
- expect(@lastRequest().data()['field1']).toEqual(['value1'])
382
- expect(@lastRequest().data()['field2']).toEqual(['value2'])
383
- expect(@lastRequest().requestHeaders['X-Up-Target']).toEqual('.response')
384
-
385
- @respondWith
386
- responseHeaders:
387
- 'X-Up-Location': '/redirect-target'
388
- 'X-Up-Method': 'GET'
389
- responseText: """
390
- <div class='before'>
391
- new-before
392
- </div>
393
-
394
- <div class="response">
395
- new-text
396
- </div>
397
-
398
- <div class='after'>
399
- new-after
400
- </div>
401
- """
402
-
403
- next =>
404
- expect(up.browser.url()).toMatchUrl('/redirect-target')
405
- expect('.response').toHaveText('new-text')
406
- # See that containers outside the form have not changed
407
- expect('.before').not.toHaveText('old-before')
408
- expect('.after').not.toHaveText('old-after')
409
-
410
- it "places the response into the form and doesn't update the browser URL if the submission returns a 5xx status code", asyncSpec (next) ->
411
- up.submit(@$form)
412
-
413
- next =>
414
- @respondWith
415
- status: 500
416
- contentType: 'text/html'
417
- responseText:
418
- """
419
- <div class='before'>
420
- new-before
421
- </div>
422
-
423
- <form>
424
- error-messages
425
- </form>
426
-
427
- <div class='after'>
428
- new-after
429
- </div>
430
- """
431
-
432
- next =>
433
- expect(up.browser.url()).toEqual(@hrefBeforeExample)
434
- expect('.response').toHaveText('old-text')
435
- expect('form').toHaveText('error-messages')
436
- # See that containers outside the form have not changed
437
- expect('.before').not.toHaveText('old-before')
438
- expect('.after').not.toHaveText('old-after')
439
-
440
- expect(window).toHaveUnhandledRejections() if REJECTION_EVENTS_SUPPORTED
441
-
442
-
443
- it 'respects X-Up-Method and X-Up-Location response headers so the server can show that it redirected to a GET URL', asyncSpec (next) ->
444
- up.submit(@$form)
445
-
446
- next =>
447
- @respondWith
448
- status: 200
449
- contentType: 'text/html'
450
- responseHeaders:
451
- 'X-Up-Location': '/other-path'
452
- 'X-Up-Method': 'GET'
453
- responseText:
454
- """
455
- <div class="response">
456
- new-text
457
- </div>
458
- """
459
-
460
- next =>
461
- expect(up.browser.url()).toMatchUrl('/other-path')
462
-
463
- it 'submits the form to the current URL if the form has no [action] attribute', asyncSpec (next) ->
464
- form = fixture('form')
465
- hrefBeforeSubmit = location.href
466
-
467
- up.submit(form)
468
-
469
- next =>
470
- expect(@lastRequest().url).toMatchUrl(hrefBeforeSubmit)
471
-
472
- describe 'handling of query params in the [action] URL', ->
473
-
474
- describe 'for forms with GET method', ->
475
-
476
- it 'discards query params from an [action] attribute (like browsers do)', asyncSpec (next) ->
477
- # See design/query-params-in-form-actions/cases.html for
478
- # a demo of vanilla browser behavior.
479
-
480
- form = fixture('form[method="GET"][action="/action?foo=value-from-action"]')
481
- input1 = e.affix(form, 'input[name="foo"][value="value-from-input"]')
482
- input2 = e.affix(form, 'input[name="foo"][value="other-value-from-input"]')
483
-
484
- up.submit(form)
485
-
486
- next =>
487
- expect(@lastRequest().url).toMatchUrl('/action?foo=value-from-input&foo=other-value-from-input')
488
-
489
- describe 'for forms with POST method' ,->
490
-
491
- it 'keeps all query params in the URL', asyncSpec (next) ->
492
-
493
- form = fixture('form[method="POST"][action="/action?foo=value-from-action"]')
494
- input1 = e.affix(form, 'input[name="foo"][value="value-from-input"]')
495
- input2 = e.affix(form, 'input[name="foo"][value="other-value-from-input"]')
496
-
497
- up.submit(form)
498
-
499
- next =>
500
- expect(@lastRequest().url).toMatchUrl('/action?foo=value-from-action')
501
- expect(@lastRequest().data()['foo']).toEqual ['value-from-input', 'other-value-from-input']
502
-
503
- describe 'with { history } option', ->
504
-
505
- it 'uses the given URL as the new browser location if the request succeeded', asyncSpec (next) ->
506
- up.submit(@$form, history: '/given-path')
507
- next => @respondWith('<div class="response">new-text</div>')
508
- next => expect(up.browser.url()).toMatchUrl('/given-path')
509
-
510
- it 'keeps the current browser location if the request failed', asyncSpec (next) ->
511
- up.submit(@$form, history: '/given-path', failTarget: '.response')
512
- next => @respondWith('<div class="response">new-text</div>', status: 500)
513
- next => expect(up.browser.url()).toEqual(@hrefBeforeExample)
514
-
515
- it 'keeps the current browser location if the option is set to false', asyncSpec (next) ->
516
- up.submit(@$form, history: false)
517
- next => @respondWith('<div class="response">new-text</div>')
518
- next =>expect(up.browser.url()).toEqual(@hrefBeforeExample)
519
-
520
- describe 'revealing', ->
521
-
522
- it 'reaveals the target fragment if the submission succeeds', asyncSpec (next) ->
523
- $form = $fixture('form[action="/action"][up-target=".target"]')
524
- $target = $fixture('.target')
525
-
526
- revealStub = up.viewport.knife.mock('reveal')
527
-
528
- up.submit($form)
529
-
530
- next =>
531
- @respondWith('<div class="target">new text</div>')
532
-
533
- next =>
534
- expect(revealStub).toHaveBeenCalled()
535
- expect(revealStub.calls.mostRecent().args[0]).toMatchSelector('.target')
536
-
537
- it 'reveals the form if the submission fails', asyncSpec (next) ->
538
- $form = $fixture('form#foo-form[action="/action"][up-target=".target"]')
539
- $target = $fixture('.target')
540
-
541
- revealStub = up.viewport.knife.mock('reveal')
542
-
543
- up.submit($form)
544
-
545
- next =>
546
- @respondWith
547
- status: 500,
548
- responseText: """
549
- <form id="foo-form">
550
- Errors here
551
- </form>
552
- """
553
-
554
- next =>
555
- expect(revealStub).toHaveBeenCalled()
556
- expect(revealStub.calls.mostRecent().args[0]).toMatchSelector('#foo-form')
557
-
558
-
559
- describe 'with { reveal } option', ->
560
-
561
- it 'allows to reveal a different selector', asyncSpec (next) ->
562
- $form = $fixture('form[action="/action"][up-target=".target"]')
563
- $target = $fixture('.target')
564
- $other = $fixture('.other')
565
-
566
- revealStub = up.viewport.knife.mock('reveal')
567
-
568
- up.submit($form, reveal: '.other')
569
-
570
- next =>
571
- @respondWith """
572
- <div class="target">
573
- new text
574
- </div>
575
- <div class="other">
576
- new other
577
- </div>
578
- """
579
-
580
- next =>
581
- expect(revealStub).toHaveBeenCalled()
582
- expect(revealStub.calls.mostRecent().args[0]).toMatchSelector('.other')
583
-
584
- it 'still reveals the form for a failed submission', asyncSpec (next) ->
585
- $form = $fixture('form#foo-form[action="/action"][up-target=".target"]')
586
- $target = $fixture('.target')
587
- $other = $fixture('.other')
588
-
589
- revealStub = up.viewport.knife.mock('reveal')
590
-
591
- up.submit($form, reveal: '.other')
592
-
593
- next =>
594
- @respondWith
595
- status: 500,
596
- responseText: """
597
- <form id="foo-form">
598
- Errors here
599
- </form>
600
- """
601
-
602
- next =>
603
- expect(revealStub).toHaveBeenCalled()
604
- expect(revealStub.calls.mostRecent().args[0]).toMatchSelector('#foo-form')
605
-
606
- it 'allows to refer to this form as "&" in the selector', asyncSpec (next) ->
607
- $form = $fixture('form#foo-form[action="/action"][up-target="#foo-form"]')
608
-
609
- revealStub = up.viewport.knife.mock('reveal')
610
-
611
- up.submit($form, reveal: '& .form-child')
612
-
613
- next =>
614
- @respondWith """
615
- <div class="target">
616
- new text
617
- </div>
618
-
619
- <form id="foo-form">
620
- <div class="form-child">other</div>
621
- </form>
622
- """
623
-
624
- next =>
625
- expect(revealStub).toHaveBeenCalled()
626
- expect(revealStub.calls.mostRecent().args[0]).toEqual(e.first('#foo-form .form-child'))
627
-
628
- describe 'with { failReveal } option', ->
629
-
630
- it 'reveals the given selector for a failed submission', asyncSpec (next) ->
631
- $form = $fixture('form#foo-form[action="/action"][up-target=".target"]')
632
- $target = $fixture('.target')
633
- $other = $fixture('.other')
634
-
635
- revealStub = up.viewport.knife.mock('reveal')
636
-
637
- up.submit($form, reveal: '.other', failReveal: '.error')
638
-
639
- next =>
640
- @respondWith
641
- status: 500,
642
- responseText: """
643
- <form id="foo-form">
644
- <div class="error">Errors here</div>
645
- </form>
646
- """
647
-
648
- next =>
649
- expect(revealStub).toHaveBeenCalled()
650
- expect(revealStub.calls.mostRecent().args[0]).toMatchSelector('.error')
651
-
652
- it 'allows to refer to this form as "&" in the selector', asyncSpec (next) ->
653
- $form = $fixture('form#foo-form[action="/action"][up-target=".target"][up-fail-reveal="#foo-form .form-child"]')
654
- $target = $fixture('.target')
655
-
656
- revealStub = up.viewport.knife.mock('reveal')
657
-
658
- up.submit($form, reveal: '& .form-child')
659
-
660
- next =>
661
- @respondWith
662
- status: 500
663
- responseText: """
664
- <div class="target">
665
- new text
666
- </div>
667
-
668
- <form id="foo-form">
669
- <div class="form-child">other</div>
670
- </form>
671
- """
672
-
673
- next =>
674
- expect(revealStub).toHaveBeenCalled()
675
- expect(revealStub.calls.mostRecent().args[0]).toEqual(e.first('#foo-form .form-child'))
676
-
677
- describe 'in a form with file inputs', ->
678
-
679
- beforeEach ->
680
- @$form.affix('input[name="text-field"][type="text"]').val("value")
681
- @$form.affix('input[name="file-field"][type="file"]')
682
-
683
- it 'transfers the form fields via FormData', asyncSpec (next) ->
684
- up.submit(@$form)
685
- next =>
686
- rawData = @lastRequest().params
687
- expect(u.isFormData(rawData)).toBe(true)
688
-
689
- describeFallback 'canPushState', ->
690
-
691
- it 'falls back to a vanilla form submission', asyncSpec (next) ->
692
- $form = $fixture('form[action="/path/to"][method="put"][up-target=".response"]')
693
- form = $form.get(0)
694
- spyOn(form, 'submit')
695
-
696
- up.submit($form)
697
-
698
- next => expect(form.submit).toHaveBeenCalled()
699
-
700
- describe 'unobtrusive behavior', ->
701
-
702
- describe 'form[up-target]', ->
703
-
704
- it 'submits the form with AJAX and replaces the [up-target] selector', asyncSpec (next) ->
705
- up.history.config.enabled = true
706
-
707
- $fixture('.response').text('old text')
708
-
709
- $form = $fixture('form[action="/form-target"][method="put"][up-target=".response"]')
710
- $form.append('<input name="field1" value="value1">')
711
- $form.append('<input name="field2" value="value2">')
712
- $submitButton = $form.affix('input[type="submit"][name="submit-button"][value="submit-button-value"]')
713
- up.hello($form)
714
-
715
- Trigger.clickSequence($submitButton)
716
-
717
- next =>
718
- params = @lastRequest().data()
719
- expect(params['field1']).toEqual(['value1'])
720
- expect(params['field2']).toEqual(['value2'])
721
-
722
- next =>
723
- @respondWith """
724
- <div class="response">
725
- new text
726
- </div>
727
- """
728
-
729
- next =>
730
- expect('.response').toHaveText('new text')
731
-
732
- it 'allows to refer to this form as "&" in the target selector', asyncSpec (next) ->
733
- $form = $fixture('form.my-form[action="/form-target"][up-target="&"]').text('old form text')
734
- $submitButton = $form.affix('input[type="submit"]')
735
- up.hello($form)
736
-
737
- Trigger.clickSequence($submitButton)
738
-
739
- next =>
740
- @respondWith """
741
- <form class="my-form">
742
- new form text
743
- </form>
744
- """
745
-
746
- next =>
747
- expect('.my-form').toHaveText('new form text')
748
-
749
- describe 'when the server responds with an error code', ->
750
-
751
- it 'replaces the form instead of the [up-target] selector', asyncSpec (next) ->
752
- up.history.config.enabled = true
753
-
754
- $fixture('.response').text('old text')
755
-
756
- $form = $fixture('form.test-form[action="/form-target"][method="put"][up-target=".response"]')
757
- $form.append('<input name="field1" value="value1">')
758
- $form.append('<input name="field2" value="value2">')
759
- $submitButton = $form.affix('input[type="submit"][name="submit-button"][value="submit-button-value"]')
760
- up.hello($form)
761
-
762
- Trigger.clickSequence($submitButton)
763
-
764
- next =>
765
- params = @lastRequest().data()
766
- expect(params['field1']).toEqual(['value1'])
767
- expect(params['field2']).toEqual(['value2'])
768
-
769
- next =>
770
- @respondWith
771
- status: 500
772
- responseText: """
773
- <form class="test-form">
774
- validation errors
775
- </form>
776
- """
777
-
778
- next =>
779
- expect('.response').toHaveText('old text')
780
- expect('form.test-form').toHaveText('validation errors')
781
-
782
- # Since there isn't anyone who could handle the rejection inside
783
- # the event handler, our handler mutes the rejection.
784
- expect(window).not.toHaveUnhandledRejections() if REJECTION_EVENTS_SUPPORTED
785
-
786
- it 'updates a given selector when an [up-fail-target] is given', asyncSpec (next) ->
787
- $form = $fixture('form.my-form[action="/path"][up-target=".target"][up-fail-target=".errors"]').text('old form text')
788
- $errors = $fixture('.target').text('old target text')
789
- $errors = $fixture('.errors').text('old errors text')
790
-
791
- $submitButton = $form.affix('input[type="submit"]')
792
- up.hello($form)
793
-
794
- Trigger.clickSequence($submitButton)
795
-
796
- next =>
797
- @respondWith
798
- status: 500
799
- responseText: """
800
- <form class="my-form">
801
- new form text
802
- </form>
803
-
804
- <div class="errors">
805
- new errors text
806
- </div>
807
- """
808
-
809
- next =>
810
- expect('.my-form').toHaveText('old form text')
811
- expect('.target').toHaveText('old target text')
812
- expect('.errors').toHaveText('new errors text')
813
-
814
- it 'allows to refer to this form as "&" in the [up-fail-target] selector', asyncSpec (next) ->
815
- $form = $fixture('form.my-form[action="/form-target"][up-target=".target"][up-fail-target="&"]').text('old form text')
816
- $target = $fixture('.target').text('old target text')
817
-
818
- $submitButton = $form.affix('input[type="submit"]')
819
- up.hello($form)
820
-
821
- Trigger.clickSequence($submitButton)
822
-
823
- next =>
824
- @respondWith
825
- status: 500,
826
- responseText: """
827
- <form class="my-form">
828
- new form text
829
- </form>
830
- """
831
-
832
- next =>
833
- expect('.target').toHaveText('old target text')
834
- expect('.my-form').toHaveText('new form text')
835
-
836
- describe 'submit buttons', ->
837
-
838
- it 'includes the clicked submit button in the params', asyncSpec (next) ->
839
- $form = $fixture('form[action="/action"][up-target=".target"]')
840
- $textField = $form.affix('input[type="text"][name="text-field"][value="text-field-value"]')
841
- $submitButton = $form.affix('input[type="submit"][name="submit-button"][value="submit-button-value"]')
842
- up.hello($form)
843
- Trigger.clickSequence($submitButton)
844
-
845
- next =>
846
- params = @lastRequest().data()
847
- expect(params['text-field']).toEqual(['text-field-value'])
848
- expect(params['submit-button']).toEqual(['submit-button-value'])
849
-
850
- it 'excludes an unused submit button in the params', asyncSpec (next) ->
851
- $form = $fixture('form[action="/action"][up-target=".target"]')
852
- $textField = $form.affix('input[type="text"][name="text-field"][value="text-field-value"]')
853
- $submitButton1 = $form.affix('input[type="submit"][name="submit-button-1"][value="submit-button-1-value"]')
854
- $submitButton2 = $form.affix('input[type="submit"][name="submit-button-2"][value="submit-button-2-value"]')
855
- up.hello($form)
856
- Trigger.clickSequence($submitButton2)
857
-
858
- next =>
859
- params = @lastRequest().data()
860
- expect(params['text-field']).toEqual(['text-field-value'])
861
- expect(params['submit-button-1']).toBeUndefined()
862
- expect(params['submit-button-2']).toEqual(['submit-button-2-value'])
863
-
864
- it 'includes the first submit button if the form was submitted with enter', asyncSpec (next) ->
865
- $form = $fixture('form[action="/action"][up-target=".target"]')
866
- $textField = $form.affix('input[type="text"][name="text-field"][value="text-field-value"]')
867
- $submitButton1 = $form.affix('input[type="submit"][name="submit-button-1"][value="submit-button-1-value"]')
868
- $submitButton2 = $form.affix('input[type="submit"][name="submit-button-2"][value="submit-button-2-value"]')
869
- up.hello($form)
870
-
871
- Trigger.submit($form) # sorry
872
-
873
- next =>
874
- params = @lastRequest().data()
875
- expect(params['text-field']).toEqual(['text-field-value'])
876
- expect(params['submit-button-1']).toEqual(['submit-button-1-value'])
877
- expect(params['submit-button-2']).toBeUndefined()
878
-
879
- it 'does not explode if the form has no submit buttons', asyncSpec (next) ->
880
- $form = $fixture('form[action="/action"][up-target=".target"]')
881
- $textField = $form.affix('input[type="text"][name="text-field"][value="text-field-value"]')
882
- up.hello($form)
883
-
884
- Trigger.submit($form) # sorry
885
-
886
- next =>
887
- params = @lastRequest().data()
888
- keys = Object.keys(params)
889
- expect(keys).toEqual(['text-field'])
890
-
891
- describe 'input[up-autosubmit]', ->
892
-
893
- it 'submits the form when a change is observed in the given form field', asyncSpec (next) ->
894
- $form = $fixture('form')
895
- $field = $form.affix('input[up-autosubmit][name="input-name"][value="old-value"]')
896
- up.hello($field)
897
- submitSpy = up.form.knife.mock('submit').and.returnValue(u.unresolvablePromise())
898
- $field.val('new-value')
899
- Trigger.change($field)
900
- next => expect(submitSpy).toHaveBeenCalled()
901
-
902
- it 'submits the form when a change is observed on a container for a radio button group', asyncSpec (next) ->
903
- form = fixture('form')
904
- group = e.affix(form, '.group[up-autosubmit][up-delay=0]')
905
- radio1 = e.affix(group, 'input[type=radio][name=foo][value=1]')
906
- radio2 = e.affix(group, 'input[type=radio][name=foo][value=2]')
907
- up.hello(form)
908
- submitSpy = up.form.knife.mock('submit').and.returnValue(Promise.reject())
909
- Trigger.clickSequence(radio1)
910
- next =>
911
- expect(submitSpy.calls.count()).toBe(1)
912
- Trigger.clickSequence(radio2)
913
- next =>
914
- expect(submitSpy.calls.count()).toBe(2)
915
- Trigger.clickSequence(radio1)
916
- next =>
917
- expect(submitSpy.calls.count()).toBe(3)
918
-
919
- describe 'form[up-autosubmit]', ->
920
-
921
- it 'submits the form when a change is observed in any of its fields', asyncSpec (next) ->
922
- $form = $fixture('form[up-autosubmit]')
923
- $field = $form.affix('input[name="input-name"][value="old-value"]')
924
- up.hello($form)
925
- submitSpy = up.form.knife.mock('submit').and.returnValue(u.unresolvablePromise())
926
- $field.val('new-value')
927
- Trigger.change($field)
928
- next => expect(submitSpy).toHaveBeenCalled()
929
-
930
- describe 'with [up-delay] modifier', ->
931
-
932
- it 'debounces the form submission', asyncSpec (next) ->
933
- $form = $fixture('form[up-autosubmit][up-delay="50"]')
934
- $field = $form.affix('input[name="input-name"][value="old-value"]')
935
- up.hello($form)
936
- submitSpy = up.form.knife.mock('submit').and.returnValue(u.unresolvablePromise())
937
- $field.val('new-value-1')
938
- Trigger.change($field)
939
- $field.val('new-value-2')
940
- Trigger.change($field)
941
-
942
- next =>
943
- expect(submitSpy.calls.count()).toBe(0)
944
-
945
- next.after 80, =>
946
- expect(submitSpy.calls.count()).toBe(1)
947
-
948
- describe 'input[up-observe]', ->
949
-
950
- afterEach ->
951
- window.observeCallbackSpy = undefined
952
-
953
- it 'runs the JavaScript code in the attribute value when a change is observed in the field', asyncSpec (next) ->
954
- $form = $fixture('form')
955
- window.observeCallbackSpy = jasmine.createSpy('observe callback')
956
- $field = $form.affix('input[name="input-name"][value="old-value"][up-observe="window.observeCallbackSpy(value, name)"]')
957
- up.hello($form)
958
- $field.val('new-value')
959
- Trigger.change($field)
960
-
961
- next =>
962
- expect(window.observeCallbackSpy).toHaveBeenCalledWith('new-value', 'input-name')
963
-
964
- describe 'with [up-delay] modifier', ->
965
-
966
- it 'debounces the callback', asyncSpec (next) ->
967
- $form = $fixture('form')
968
- window.observeCallbackSpy = jasmine.createSpy('observe callback')
969
- $field = $form.affix('input[name="input-name"][value="old-value"][up-observe="window.observeCallbackSpy()"][up-delay="50"]')
970
- up.hello($form)
971
- $field.val('new-value')
972
- Trigger.change($field)
973
-
974
- next => expect(window.observeCallbackSpy).not.toHaveBeenCalled()
975
- next.after 80, => expect(window.observeCallbackSpy).toHaveBeenCalled()
976
-
977
- describe 'form[up-observe]', ->
978
-
979
- afterEach ->
980
- window.observeCallbackSpy = undefined
981
-
982
- it 'runs the JavaScript code in the attribute value when a change is observed in any contained field', asyncSpec (next) ->
983
- window.observeCallbackSpy = jasmine.createSpy('observe callback')
984
- $form = $fixture('form[up-observe="window.observeCallbackSpy(value, name)"]')
985
- $field1 = $form.affix('input[name="field1"][value="field1-old-value"]')
986
- $field2 = $form.affix('input[name="field2"][value="field2-old-value"]')
987
- up.hello($form)
988
- $field1.val('field1-new-value')
989
- Trigger.change($field1)
990
-
991
- next =>
992
- expect(window.observeCallbackSpy.calls.allArgs()).toEqual [
993
- ['field1-new-value', 'field1']
994
- ]
995
-
996
- $field2.val('field2-new-value')
997
- Trigger.change($field2)
998
-
999
- next =>
1000
- expect(window.observeCallbackSpy.calls.allArgs()).toEqual [
1001
- ['field1-new-value', 'field1'],
1002
- ['field2-new-value', 'field2']
1003
- ]
1004
-
1005
- describe 'input[up-validate]', ->
1006
-
1007
- describe 'when a selector is given', ->
1008
-
1009
- it "submits the input's form with an 'X-Up-Validate' header and replaces the selector with the response", asyncSpec (next) ->
1010
-
1011
- $form = $fixture('form[action="/path/to"]')
1012
- $group = $("""
1013
- <div class="field-group">
1014
- <input name="user" value="judy" up-validate=".field-group:has(&)">
1015
- </div>
1016
- """).appendTo($form)
1017
-
1018
- Trigger.change($group.find('input'))
1019
-
1020
- next =>
1021
- request = @lastRequest()
1022
- expect(request.requestHeaders['X-Up-Validate']).toEqual('user')
1023
- expect(request.requestHeaders['X-Up-Target']).toEqual('.field-group:has(input[name="user"])')
1024
-
1025
- @respondWith
1026
- status: 500
1027
- responseText: """
1028
- <div class="field-group has-error">
1029
- <div class='error'>Username has already been taken</div>
1030
- <input name="user" value="judy" up-validate=".field-group:has(&)">
1031
- </div>
1032
- """
1033
-
1034
- next =>
1035
- $group = $('.field-group')
1036
- expect($group.length).toBe(1)
1037
- expect($group).toHaveClass('has-error')
1038
- expect($group).toHaveText('Username has already been taken')
1039
-
1040
- # Since there isn't anyone who could handle the rejection inside
1041
- # the event handler, our handler mutes the rejection.
1042
- expect(window).not.toHaveUnhandledRejections() if REJECTION_EVENTS_SUPPORTED
1043
-
1044
- it 'does not reveal the updated fragment (bugfix)', asyncSpec (next) ->
1045
- revealSpy = up.viewport.knife.mock('reveal').and.returnValue(Promise.resolve())
1046
-
1047
- $form = $fixture('form[action="/path/to"]')
1048
- $group = $("""
1049
- <div class="field-group">
1050
- <input name="user" value="judy" up-validate=".field-group:has(&)">
1051
- </div>
1052
- """).appendTo($form)
1053
- Trigger.change($group.find('input'))
1054
-
1055
- next =>
1056
- @respondWith """
1057
- <div class="field-group has-error">
1058
- <div class='error'>Username has already been taken</div>
1059
- <input name="user" value="judy" up-validate=".field-group:has(&)">
1060
- </div>
1061
- """
1062
-
1063
- next =>
1064
- expect(revealSpy).not.toHaveBeenCalled()
1065
-
1066
-
1067
- describe 'when no selector is given', ->
1068
-
1069
- it 'automatically finds a form group around the input field and only updates that', asyncSpec (next) ->
1070
- container = fixture('.container')
1071
- container.innerHTML = """
1072
- <form action="/users" id="registration">
1073
-
1074
- <div up-fieldset>
1075
- <input type="text" name="email" up-validate />
1076
- </div>
1077
-
1078
- <div up-fieldset>
1079
- <input type="password" name="password" up-validate />
1080
- </div>
1081
-
1082
- </form>
1083
- """
1084
- up.hello(container)
1085
-
1086
- Trigger.change $('#registration input[name=password]')
1087
-
1088
- next =>
1089
- @respondWith """
1090
- <form action="/users" id="registration">
1091
-
1092
- <div up-fieldset>
1093
- Validation message
1094
- <input type="text" name="email" up-validate />
1095
- </div>
1096
-
1097
- <div up-fieldset>
1098
- Validation message
1099
- <input type="password" name="password" up-validate />
1100
- </div>
1101
-
1102
- </form>
1103
- """
1104
-
1105
- next =>
1106
- $labels = $('#registration [up-fieldset]')
1107
- expect($labels[0]).not.toHaveText('Validation message')
1108
- expect($labels[1]).toHaveText('Validation message')
1109
-
1110
- describe 'form[up-validate]', ->
1111
-
1112
- # it 'prints an error saying that this form is not yet supported', ->
1113
-
1114
- it 'performs server-side validation for all fieldsets contained within the form', asyncSpec (next) ->
1115
- container = fixture('.container')
1116
- container.innerHTML = """
1117
- <form action="/users" id="registration" up-validate>
1118
-
1119
- <div up-fieldset>
1120
- <input type="text" name="email">
1121
- </div>
1122
-
1123
- <div up-fieldset>
1124
- <input type="password" name="password">
1125
- </div>
1126
-
1127
- </form>
1128
- """
1129
- up.hello(container)
1130
-
1131
- Trigger.change $('#registration input[name=password]')
1132
-
1133
- next =>
1134
- expect(jasmine.Ajax.requests.count()).toEqual(1)
1135
- expect(@lastRequest().requestHeaders['X-Up-Validate']).toEqual('password')
1136
- expect(@lastRequest().requestHeaders['X-Up-Target']).toEqual('[up-fieldset]:has(input[name="password"])')
1137
-
1138
-
1139
- @respondWith """
1140
- <form action="/users" id="registration" up-validate>
1141
-
1142
- <div up-fieldset>
1143
- Validation message
1144
- <input type="text" name="email">
1145
- </div>
1146
-
1147
- <div up-fieldset>
1148
- Validation message
1149
- <input type="password" name="password">
1150
- </div>
1151
-
1152
- </form>
1153
- """
1154
-
1155
- next =>
1156
- $labels = $('#registration [up-fieldset]')
1157
- expect($labels[0]).not.toHaveText('Validation message')
1158
- expect($labels[1]).toHaveText('Validation message')
1159
-
1160
- it 'only sends a single request when a radio button group changes', asyncSpec (next) ->
1161
- container = fixture('.container')
1162
- container.innerHTML = """
1163
- <form action="/users" id="registration" up-validate>
1164
-
1165
- <div up-fieldset>
1166
- <input type="radio" name="foo" value="1" checked>
1167
- <input type="radio" name="foo" value="2">
1168
- </div>
1169
-
1170
- </form>
1171
- """
1172
- up.hello(container)
1173
-
1174
- Trigger.change $('#registration input[value="2"]')
1175
-
1176
- next =>
1177
- expect(jasmine.Ajax.requests.count()).toEqual(1)
1178
-
1179
- describe '[up-switch]', ->
1180
-
1181
- describe 'on a select', ->
1182
-
1183
- beforeEach ->
1184
- @$select = $fixture('select[name="select-name"][up-switch=".target"]')
1185
- @$blankOption = @$select.affix('option').text('<Please select something>').val('')
1186
- @$fooOption = @$select.affix('option[value="foo"]').text('Foo')
1187
- @$barOption = @$select.affix('option[value="bar"]').text('Bar')
1188
- @$bazOption = @$select.affix('option[value="baz"]').text('Baz')
1189
-
1190
- it "shows the target element iff its up-show-for attribute contains the select value", asyncSpec (next) ->
1191
- $target = $fixture('.target[up-show-for="something bar other"]')
1192
- up.hello(@$select)
1193
-
1194
- next =>
1195
- expect($target).toBeHidden()
1196
- @$select.val('bar')
1197
- Trigger.change(@$select)
1198
-
1199
- next =>
1200
- expect($target).toBeVisible()
1201
-
1202
- it "shows the target element iff its up-hide-for attribute doesn't contain the select value", asyncSpec (next) ->
1203
- $target = $fixture('.target[up-hide-for="something bar other"]')
1204
- up.hello(@$select)
1205
-
1206
- next =>
1207
- expect($target).toBeVisible()
1208
- @$select.val('bar')
1209
- Trigger.change(@$select)
1210
-
1211
- next =>
1212
- expect($target).toBeHidden()
1213
-
1214
- it "shows the target element iff it has neither up-show-for nor up-hide-for and the select value is present", asyncSpec (next) ->
1215
- $target = $fixture('.target')
1216
- up.hello(@$select)
1217
-
1218
- next =>
1219
- expect($target).toBeHidden()
1220
- @$select.val('bar')
1221
- Trigger.change(@$select)
1222
-
1223
- next =>
1224
- expect($target).toBeVisible()
1225
-
1226
- it "shows the target element iff its up-show-for attribute contains a value ':present' and the select value is present", asyncSpec (next) ->
1227
- $target = $fixture('.target[up-show-for=":present"]')
1228
- up.hello(@$select)
1229
-
1230
- next =>
1231
- expect($target).toBeHidden()
1232
- @$select.val('bar')
1233
- Trigger.change(@$select)
1234
-
1235
- next =>
1236
- expect($target).toBeVisible()
1237
-
1238
- it "shows the target element iff its up-show-for attribute contains a value ':blank' and the select value is blank", asyncSpec (next) ->
1239
- $target = $fixture('.target[up-show-for=":blank"]')
1240
- up.hello(@$select)
1241
-
1242
- next =>
1243
- expect($target).toBeVisible()
1244
- @$select.val('bar')
1245
- Trigger.change(@$select)
1246
-
1247
- next =>
1248
- expect($target).toBeHidden()
1249
-
1250
- describe 'on a checkbox', ->
1251
-
1252
- beforeEach ->
1253
- @$checkbox = $fixture('input[name="input-name"][type="checkbox"][value="1"][up-switch=".target"]')
1254
-
1255
- it "shows the target element iff its up-show-for attribute is :checked and the checkbox is checked", asyncSpec (next) ->
1256
- $target = $fixture('.target[up-show-for=":checked"]')
1257
- up.hello(@$checkbox)
1258
-
1259
- next =>
1260
- expect($target).toBeHidden()
1261
- @$checkbox.prop('checked', true)
1262
- Trigger.change(@$checkbox)
1263
-
1264
- next =>
1265
- expect($target).toBeVisible()
1266
-
1267
- it "shows the target element iff its up-show-for attribute is :unchecked and the checkbox is unchecked", asyncSpec (next) ->
1268
- $target = $fixture('.target[up-show-for=":unchecked"]')
1269
- up.hello(@$checkbox)
1270
-
1271
- next =>
1272
- expect($target).toBeVisible()
1273
- @$checkbox.prop('checked', true)
1274
- Trigger.change(@$checkbox)
1275
-
1276
- next =>
1277
- expect($target).toBeHidden()
1278
-
1279
- it "shows the target element iff its up-hide-for attribute is :checked and the checkbox is unchecked", asyncSpec (next) ->
1280
- $target = $fixture('.target[up-hide-for=":checked"]')
1281
- up.hello(@$checkbox)
1282
-
1283
- next =>
1284
- expect($target).toBeVisible()
1285
- @$checkbox.prop('checked', true)
1286
- Trigger.change(@$checkbox)
1287
-
1288
- next =>
1289
- expect($target).toBeHidden()
1290
-
1291
- it "shows the target element iff its up-hide-for attribute is :unchecked and the checkbox is checked", asyncSpec (next) ->
1292
- $target = $fixture('.target[up-hide-for=":unchecked"]')
1293
- up.hello(@$checkbox)
1294
-
1295
- next =>
1296
- expect($target).toBeHidden()
1297
- @$checkbox.prop('checked', true)
1298
- Trigger.change(@$checkbox)
1299
-
1300
- next =>
1301
- expect($target).toBeVisible()
1302
-
1303
- it "shows the target element iff it has neither up-show-for nor up-hide-for and the checkbox is checked", asyncSpec (next) ->
1304
- $target = $fixture('.target')
1305
- up.hello(@$checkbox)
1306
-
1307
- next =>
1308
- expect($target).toBeHidden()
1309
- @$checkbox.prop('checked', true)
1310
- Trigger.change(@$checkbox)
1311
-
1312
- next =>
1313
- expect($target).toBeVisible()
1314
-
1315
- describe 'on a group of radio buttons', ->
1316
-
1317
- beforeEach ->
1318
- @$buttons = $fixture('.radio-buttons')
1319
- @$blankButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('')
1320
- @$fooButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('foo')
1321
- @$barButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('bar')
1322
- @$bazkButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('baz')
1323
-
1324
- it "shows the target element iff its up-show-for attribute contains the selected button value", asyncSpec (next) ->
1325
- $target = $fixture('.target[up-show-for="something bar other"]')
1326
- up.hello(@$buttons)
1327
-
1328
- next =>
1329
- expect($target).toBeHidden()
1330
- @$barButton.prop('checked', true)
1331
- Trigger.change(@$barButton)
1332
-
1333
- next =>
1334
- expect($target).toBeVisible()
1335
-
1336
- it "shows the target element iff its up-hide-for attribute doesn't contain the selected button value", asyncSpec (next) ->
1337
- $target = $fixture('.target[up-hide-for="something bar other"]')
1338
- up.hello(@$buttons)
1339
-
1340
- next =>
1341
- expect($target).toBeVisible()
1342
- @$barButton.prop('checked', true)
1343
- Trigger.change(@$barButton)
1344
-
1345
- next =>
1346
- expect($target).toBeHidden()
1347
-
1348
- it "shows the target element iff it has neither up-show-for nor up-hide-for and the selected button value is present", asyncSpec (next) ->
1349
- $target = $fixture('.target')
1350
- up.hello(@$buttons)
1351
-
1352
- next =>
1353
- expect($target).toBeHidden()
1354
- @$barButton.prop('checked', true)
1355
- Trigger.change(@$barButton)
1356
-
1357
- next =>
1358
- expect($target).toBeVisible()
1359
-
1360
- it "shows the target element iff its up-show-for attribute contains a value ':present' and the selected button value is present", asyncSpec (next) ->
1361
- $target = $fixture('.target[up-show-for=":present"]')
1362
- up.hello(@$buttons)
1363
-
1364
- next =>
1365
- expect($target).toBeHidden()
1366
- @$blankButton.prop('checked', true)
1367
- Trigger.change(@$blankButton)
1368
-
1369
- next =>
1370
- expect($target).toBeHidden()
1371
- @$barButton.prop('checked', true)
1372
- Trigger.change(@$barButton)
1373
-
1374
- next =>
1375
- expect($target).toBeVisible()
1376
-
1377
- it "shows the target element iff its up-show-for attribute contains a value ':blank' and the selected button value is blank", asyncSpec (next) ->
1378
- $target = $fixture('.target[up-show-for=":blank"]')
1379
- up.hello(@$buttons)
1380
-
1381
- next =>
1382
- expect($target).toBeVisible()
1383
- @$blankButton.prop('checked', true)
1384
- Trigger.change(@$blankButton)
1385
-
1386
- next =>
1387
- expect($target).toBeVisible()
1388
- @$barButton.prop('checked', true)
1389
- Trigger.change(@$barButton)
1390
-
1391
- next =>
1392
- expect($target).toBeHidden()
1393
-
1394
- it "shows the target element iff its up-show-for attribute contains a value ':checked' and any button is checked", asyncSpec (next) ->
1395
- $target = $fixture('.target[up-show-for=":checked"]')
1396
- up.hello(@$buttons)
1397
-
1398
- next =>
1399
- expect($target).toBeHidden()
1400
- @$blankButton.prop('checked', true)
1401
- Trigger.change(@$blankButton)
1402
-
1403
- next =>
1404
- expect($target).toBeVisible()
1405
-
1406
- it "shows the target element iff its up-show-for attribute contains a value ':unchecked' and no button is checked", asyncSpec (next) ->
1407
- $target = $fixture('.target[up-show-for=":unchecked"]')
1408
- up.hello(@$buttons)
1409
-
1410
- next =>
1411
- expect($target).toBeVisible()
1412
- @$blankButton.prop('checked', true)
1413
- Trigger.change(@$blankButton)
1414
-
1415
- next =>
1416
- expect($target).toBeHidden()
1417
-
1418
- describe 'on a text input', ->
1419
-
1420
- beforeEach ->
1421
- @$textInput = $fixture('input[name="input-name"][type="text"][up-switch=".target"]')
1422
-
1423
- it "shows the target element iff its up-show-for attribute contains the input value", asyncSpec (next) ->
1424
- $target = $fixture('.target[up-show-for="something bar other"]')
1425
- up.hello(@$textInput)
1426
-
1427
- next =>
1428
- expect($target).toBeHidden()
1429
- @$textInput.val('bar')
1430
- Trigger.change(@$textInput)
1431
-
1432
- next =>
1433
- expect($target).toBeVisible()
1434
-
1435
- it "shows the target element iff its up-hide-for attribute doesn't contain the input value", asyncSpec (next) ->
1436
- $target = $fixture('.target[up-hide-for="something bar other"]')
1437
- up.hello(@$textInput)
1438
-
1439
- next =>
1440
- expect($target).toBeVisible()
1441
- @$textInput.val('bar')
1442
- Trigger.change(@$textInput)
1443
-
1444
- next =>
1445
- expect($target).toBeHidden()
1446
-
1447
- it "shows the target element iff it has neither up-show-for nor up-hide-for and the input value is present", asyncSpec (next) ->
1448
- $target = $fixture('.target')
1449
- up.hello(@$textInput)
1450
-
1451
- next =>
1452
- expect($target).toBeHidden()
1453
- @$textInput.val('bar')
1454
- Trigger.change(@$textInput)
1455
-
1456
- next =>
1457
- expect($target).toBeVisible()
1458
-
1459
- it "shows the target element iff its up-show-for attribute contains a value ':present' and the input value is present", asyncSpec (next) ->
1460
- $target = $fixture('.target[up-show-for=":present"]')
1461
- up.hello(@$textInput)
1462
-
1463
- next =>
1464
- expect($target).toBeHidden()
1465
- @$textInput.val('bar')
1466
- Trigger.change(@$textInput)
1467
-
1468
- next =>
1469
- expect($target).toBeVisible()
1470
-
1471
- it "shows the target element iff its up-show-for attribute contains a value ':blank' and the input value is blank", asyncSpec (next) ->
1472
- $target = $fixture('.target[up-show-for=":blank"]')
1473
- up.hello(@$textInput)
1474
-
1475
- next =>
1476
- expect($target).toBeVisible()
1477
- @$textInput.val('bar')
1478
- Trigger.change(@$textInput)
1479
-
1480
- next =>
1481
- expect($target).toBeHidden()
1482
-
1483
- describe 'when an [up-show-for] element is dynamically inserted later', ->
1484
-
1485
- it "shows the element iff it matches the [up-switch] control's value", asyncSpec (next) ->
1486
- $select = $fixture('select[name="select-name"][up-switch=".target"]')
1487
- $select.affix('option[value="foo"]').text('Foo')
1488
- $select.affix('option[value="bar"]').text('Bar')
1489
- $select.val('foo')
1490
- up.hello($select)
1491
-
1492
- next =>
1493
- # New target enters the DOM after [up-switch] has been compiled
1494
- @$target = $fixture('.target[up-show-for="bar"]')
1495
- up.hello(@$target)
1496
-
1497
- next =>
1498
- expect(@$target).toBeHidden()
1499
-
1500
- next =>
1501
- # Check that the new element will notify subsequent changes
1502
- $select.val('bar')
1503
- Trigger.change($select)
1504
- expect(@$target).toBeVisible()
1505
-
1506
- it "doesn't re-switch targets that were part of the original compile run", asyncSpec (next) ->
1507
- $container = $fixture('.container')
1508
-
1509
- $select = $container.affix('select[name="select-name"][up-switch=".target"]')
1510
- $select.affix('option[value="foo"]').text('Foo')
1511
- $select.affix('option[value="bar"]').text('Bar')
1512
- $select.val('foo')
1513
- $existingTarget = $container.affix('.target.existing[up-show-for="bar"]')
1514
-
1515
- switchTargetSpy = up.form.knife.mock('switchTarget').and.callThrough()
1516
-
1517
- up.hello($container)
1518
-
1519
- next =>
1520
- # New target enters the DOM after [up-switch] has been compiled
1521
- @$lateTarget = $container.affix('.target.late[up-show-for="bar"]')
1522
- up.hello(@$lateTarget)
1523
-
1524
- next =>
1525
- expect(switchTargetSpy.calls.count()).toBe(2)
1526
- expect(switchTargetSpy.calls.argsFor(0)[0]).toEqual($existingTarget[0])
1527
- expect(switchTargetSpy.calls.argsFor(1)[0]).toEqual(@$lateTarget[0])