unpoly-rails 0.57.0 → 0.60.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +393 -1
  3. data/Gemfile.lock +5 -2
  4. data/README.md +1 -1
  5. data/README_RAILS.md +1 -1
  6. data/Rakefile +10 -1
  7. data/design/es6.js +32 -0
  8. data/design/ie11.txt +9 -0
  9. data/design/measure_jquery/element_list.js +41 -0
  10. data/design/measure_jquery/up.on_vs_addEventListener.js +56 -0
  11. data/design/todo_jquery.txt +13 -0
  12. data/dist/unpoly-bootstrap3.js +8 -8
  13. data/dist/unpoly-bootstrap3.min.js +1 -1
  14. data/dist/unpoly.css +22 -20
  15. data/dist/unpoly.js +6990 -5336
  16. data/dist/unpoly.min.css +1 -1
  17. data/dist/unpoly.min.js +4 -4
  18. data/lib/assets/javascripts/unpoly-bootstrap3/viewport-ext.coffee +5 -0
  19. data/lib/assets/javascripts/unpoly.coffee +8 -6
  20. data/lib/assets/javascripts/unpoly/browser.coffee.erb +23 -118
  21. data/lib/assets/javascripts/unpoly/classes/body_shifter.coffee +36 -0
  22. data/lib/assets/javascripts/unpoly/classes/cache.coffee +4 -4
  23. data/lib/assets/javascripts/unpoly/classes/compile_pass.coffee +45 -39
  24. data/lib/assets/javascripts/unpoly/classes/config.coffee +9 -0
  25. data/lib/assets/javascripts/unpoly/classes/css_transition.coffee +18 -27
  26. data/lib/assets/javascripts/unpoly/classes/divertible_chain.coffee +39 -0
  27. data/lib/assets/javascripts/unpoly/classes/event_listener.coffee +116 -0
  28. data/lib/assets/javascripts/unpoly/classes/extract_cascade.coffee +8 -8
  29. data/lib/assets/javascripts/unpoly/classes/extract_plan.coffee +19 -19
  30. data/lib/assets/javascripts/unpoly/classes/field_observer.coffee +54 -31
  31. data/lib/assets/javascripts/unpoly/classes/{focus_tracker.coffee → focus_follower.coffee} +2 -2
  32. data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +25 -25
  33. data/lib/assets/javascripts/unpoly/classes/html_parser.coffee +4 -11
  34. data/lib/assets/javascripts/unpoly/classes/motion_controller.coffee +157 -0
  35. data/lib/assets/javascripts/unpoly/classes/params.coffee.erb +525 -0
  36. data/lib/assets/javascripts/unpoly/classes/record.coffee +8 -2
  37. data/lib/assets/javascripts/unpoly/classes/rect.js +21 -0
  38. data/lib/assets/javascripts/unpoly/classes/request.coffee +41 -35
  39. data/lib/assets/javascripts/unpoly/classes/response.coffee +7 -3
  40. data/lib/assets/javascripts/unpoly/classes/reveal_motion.coffee +102 -0
  41. data/lib/assets/javascripts/unpoly/classes/scroll_motion.coffee +67 -0
  42. data/lib/assets/javascripts/unpoly/classes/selector.coffee +60 -0
  43. data/lib/assets/javascripts/unpoly/classes/tether.coffee +105 -0
  44. data/lib/assets/javascripts/unpoly/classes/url_set.coffee +12 -7
  45. data/lib/assets/javascripts/unpoly/element.coffee.erb +1126 -0
  46. data/lib/assets/javascripts/unpoly/event.coffee.erb +437 -0
  47. data/lib/assets/javascripts/unpoly/feedback.coffee +73 -94
  48. data/lib/assets/javascripts/unpoly/form.coffee.erb +188 -181
  49. data/lib/assets/javascripts/unpoly/{dom.coffee.erb → fragment.coffee.erb} +250 -283
  50. data/lib/assets/javascripts/unpoly/framework.coffee +67 -0
  51. data/lib/assets/javascripts/unpoly/history.coffee +29 -28
  52. data/lib/assets/javascripts/unpoly/legacy.coffee +60 -0
  53. data/lib/assets/javascripts/unpoly/link.coffee.erb +127 -119
  54. data/lib/assets/javascripts/unpoly/log.coffee +99 -19
  55. data/lib/assets/javascripts/unpoly/modal.coffee.erb +95 -118
  56. data/lib/assets/javascripts/unpoly/motion.coffee.erb +158 -138
  57. data/lib/assets/javascripts/unpoly/namespace.coffee.erb +0 -5
  58. data/lib/assets/javascripts/unpoly/popup.coffee.erb +119 -102
  59. data/lib/assets/javascripts/unpoly/protocol.coffee +11 -15
  60. data/lib/assets/javascripts/unpoly/proxy.coffee +62 -65
  61. data/lib/assets/javascripts/unpoly/radio.coffee +3 -5
  62. data/lib/assets/javascripts/unpoly/rails.coffee +8 -9
  63. data/lib/assets/javascripts/unpoly/syntax.coffee.erb +173 -125
  64. data/lib/assets/javascripts/unpoly/toast.coffee +25 -24
  65. data/lib/assets/javascripts/unpoly/tooltip.coffee +89 -79
  66. data/lib/assets/javascripts/unpoly/util.coffee.erb +579 -1074
  67. data/lib/assets/javascripts/unpoly/{layout.coffee.erb → viewport.coffee.erb} +334 -264
  68. data/lib/assets/stylesheets/unpoly/dom.sass +1 -1
  69. data/lib/assets/stylesheets/unpoly/layout.sass +2 -0
  70. data/lib/assets/stylesheets/unpoly/popup.sass +0 -1
  71. data/lib/assets/stylesheets/unpoly/tooltip.sass +17 -12
  72. data/lib/unpoly/rails/version.rb +1 -1
  73. data/package.json +1 -2
  74. data/spec_app/Gemfile +2 -1
  75. data/spec_app/Gemfile.lock +38 -27
  76. data/spec_app/app/assets/javascripts/integration_test.coffee +1 -0
  77. data/spec_app/app/assets/javascripts/jasmine_specs.coffee +1 -2
  78. data/spec_app/app/assets/stylesheets/integration_test.sass +14 -1
  79. data/spec_app/app/controllers/scroll_test_controller.rb +5 -0
  80. data/spec_app/app/views/css_test/modal.erb +6 -6
  81. data/spec_app/app/views/css_test/popup.erb +44 -18
  82. data/spec_app/app/views/css_test/tooltip.erb +23 -4
  83. data/spec_app/app/views/error_test/trigger.erb +1 -1
  84. data/spec_app/app/views/form_test/basics/new.erb +1 -3
  85. data/spec_app/app/views/pages/start.erb +9 -2
  86. data/spec_app/app/views/reveal_test/long1.erb +1 -1
  87. data/spec_app/app/views/reveal_test/long2.erb +1 -1
  88. data/spec_app/app/views/reveal_test/within_document_viewport.erb +24 -0
  89. data/spec_app/app/views/reveal_test/within_overflowing_div_viewport.erb +28 -0
  90. data/spec_app/app/views/scroll_test/long1.erb +30 -0
  91. data/spec_app/config/routes.rb +1 -0
  92. data/spec_app/spec/javascripts/helpers/agent_detector.coffee +3 -0
  93. data/spec_app/spec/javascripts/helpers/async_sequence.js.coffee +1 -0
  94. data/spec_app/spec/javascripts/helpers/browser_switches.js.coffee +17 -5
  95. data/spec_app/spec/javascripts/helpers/enable_logging.js.coffee +1 -1
  96. data/spec_app/spec/javascripts/helpers/fixture.js.coffee +25 -0
  97. data/spec_app/spec/javascripts/helpers/jquery_no_conflict.js +1 -0
  98. data/spec_app/spec/javascripts/helpers/last_request.js.coffee +1 -0
  99. data/spec_app/spec/javascripts/helpers/mock_ajax.js.coffee +1 -1
  100. data/spec_app/spec/javascripts/helpers/parse_form_data.js.coffee +2 -2
  101. data/spec_app/spec/javascripts/helpers/protect_jasmine_runner.coffee +4 -1
  102. data/spec_app/spec/javascripts/helpers/remove_body_margin.js.coffee +3 -0
  103. data/spec_app/spec/javascripts/helpers/reset_history.js.coffee +2 -1
  104. data/spec_app/spec/javascripts/helpers/reset_knife.js.coffee +2 -2
  105. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +18 -11
  106. data/spec_app/spec/javascripts/helpers/restore_body_scroll.js.coffee +3 -0
  107. data/spec_app/spec/javascripts/helpers/show_lib_versions.coffee +3 -0
  108. data/spec_app/spec/javascripts/helpers/spec_util.coffee +47 -0
  109. data/spec_app/spec/javascripts/helpers/to_be_around.js.coffee +3 -0
  110. data/spec_app/spec/javascripts/helpers/to_be_array.coffee +5 -0
  111. data/spec_app/spec/javascripts/helpers/to_be_attached.coffee +6 -2
  112. data/spec_app/spec/javascripts/helpers/to_be_blank.js.coffee +3 -0
  113. data/spec_app/spec/javascripts/helpers/to_be_detached.coffee +6 -2
  114. data/spec_app/spec/javascripts/helpers/to_be_element.js.coffee +8 -0
  115. data/spec_app/spec/javascripts/helpers/to_be_error.coffee +3 -0
  116. data/spec_app/spec/javascripts/helpers/to_be_given.js.coffee +3 -0
  117. data/spec_app/spec/javascripts/helpers/to_be_hidden.js.coffee +8 -0
  118. data/spec_app/spec/javascripts/helpers/to_be_missing.js.coffee +3 -0
  119. data/spec_app/spec/javascripts/helpers/to_be_present.js.coffee +3 -0
  120. data/spec_app/spec/javascripts/helpers/to_be_scrolled_to.coffee +3 -0
  121. data/spec_app/spec/javascripts/helpers/to_be_visible.js.coffee +9 -0
  122. data/spec_app/spec/javascripts/helpers/to_contain.js.coffee +3 -0
  123. data/spec_app/spec/javascripts/helpers/to_end_with.js.coffee +3 -0
  124. data/spec_app/spec/javascripts/helpers/to_equal_jquery.js.coffee +1 -2
  125. data/spec_app/spec/javascripts/helpers/to_equal_node_list.coffee +7 -0
  126. data/spec_app/spec/javascripts/helpers/to_equal_via_is_equal.js.coffee +7 -0
  127. data/spec_app/spec/javascripts/helpers/to_have_class.js.coffee +10 -0
  128. data/spec_app/spec/javascripts/helpers/to_have_descendant.js.coffee +10 -0
  129. data/spec_app/spec/javascripts/helpers/to_have_length.js.coffee +8 -0
  130. data/spec_app/spec/javascripts/helpers/to_have_opacity.coffee +7 -3
  131. data/spec_app/spec/javascripts/helpers/to_have_own_property.js.coffee +3 -0
  132. data/spec_app/spec/javascripts/helpers/to_have_request_method.js.coffee +1 -0
  133. data/spec_app/spec/javascripts/helpers/to_have_text.js.coffee +9 -0
  134. data/spec_app/spec/javascripts/helpers/to_have_unhandled_rejections.coffee +0 -21
  135. data/spec_app/spec/javascripts/helpers/to_match_list.coffee +14 -0
  136. data/spec_app/spec/javascripts/helpers/to_match_selector.coffee +3 -0
  137. data/spec_app/spec/javascripts/helpers/to_match_text.js.coffee +4 -1
  138. data/spec_app/spec/javascripts/helpers/to_match_url.coffee +1 -0
  139. data/spec_app/spec/javascripts/helpers/trigger.js.coffee +91 -7
  140. data/spec_app/spec/javascripts/helpers/wait_until_dom_ready.js.coffee +3 -0
  141. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +23 -90
  142. data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +3 -0
  143. data/spec_app/spec/javascripts/up/classes/config_spec.coffee +24 -0
  144. data/spec_app/spec/javascripts/up/classes/divertible_chain_spec.coffee +45 -0
  145. data/spec_app/spec/javascripts/up/classes/focus_tracker_spec.coffee +5 -2
  146. data/spec_app/spec/javascripts/up/classes/params_spec.coffee +557 -0
  147. data/spec_app/spec/javascripts/up/classes/request_spec.coffee +7 -4
  148. data/spec_app/spec/javascripts/up/classes/scroll_motion_spec.js.coffee +51 -0
  149. data/spec_app/spec/javascripts/up/classes/store/memory_spec.js.coffee +3 -0
  150. data/spec_app/spec/javascripts/up/classes/store/session_spec.js.coffee +3 -2
  151. data/spec_app/spec/javascripts/up/element_spec.coffee +897 -0
  152. data/spec_app/spec/javascripts/up/event_spec.js.coffee +496 -0
  153. data/spec_app/spec/javascripts/up/feedback_spec.js.coffee +69 -48
  154. data/spec_app/spec/javascripts/up/form_spec.js.coffee +252 -194
  155. data/spec_app/spec/javascripts/up/{dom_spec.js.coffee → fragment_spec.js.coffee} +381 -388
  156. data/spec_app/spec/javascripts/up/history_spec.js.coffee +21 -19
  157. data/spec_app/spec/javascripts/up/jquery_spec.js.coffee +4 -0
  158. data/spec_app/spec/javascripts/up/legacy_spec.js.coffee +27 -0
  159. data/spec_app/spec/javascripts/up/link_spec.js.coffee +163 -160
  160. data/spec_app/spec/javascripts/up/log_spec.js.coffee +85 -12
  161. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +141 -123
  162. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +117 -113
  163. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +60 -77
  164. data/spec_app/spec/javascripts/up/protocol_spec.js.coffee +1 -0
  165. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +85 -78
  166. data/spec_app/spec/javascripts/up/radio_spec.js.coffee +29 -22
  167. data/spec_app/spec/javascripts/up/rails_spec.js.coffee +14 -13
  168. data/spec_app/spec/javascripts/up/spec_spec.js.coffee +9 -0
  169. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +96 -66
  170. data/spec_app/spec/javascripts/up/toast_spec.js.coffee +37 -0
  171. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +31 -47
  172. data/spec_app/spec/javascripts/up/util_spec.js.coffee +725 -562
  173. data/spec_app/spec/javascripts/up/{layout_spec.js.coffee → viewport_spec.js.coffee} +175 -149
  174. metadata +57 -19
  175. data/lib/assets/javascripts/unpoly-bootstrap3/layout-ext.coffee +0 -5
  176. data/lib/assets/javascripts/unpoly/bus.coffee.erb +0 -518
  177. data/lib/assets/javascripts/unpoly/classes/extract_step.coffee +0 -4
  178. data/lib/assets/javascripts/unpoly/classes/motion_tracker.coffee +0 -125
  179. data/lib/assets/javascripts/unpoly/params.coffee.erb +0 -522
  180. data/spec_app/spec/javascripts/helpers/append_fixture.js.coffee +0 -8
  181. data/spec_app/spec/javascripts/up/bus_spec.js.coffee +0 -210
  182. data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +0 -9
  183. data/spec_app/spec/javascripts/up/params_spec.coffee +0 -768
  184. data/spec_app/vendor/asset-libs/jasmine-fixture-1.3.4/jasmine-fixture.js +0 -433
  185. data/spec_app/vendor/asset-libs/jasmine-jquery-2.1.1/.bower.json +0 -26
  186. data/spec_app/vendor/asset-libs/jasmine-jquery-2.1.1/jasmine-jquery.js +0 -838
@@ -1,4 +0,0 @@
1
- u = up.util
2
-
3
- class up.ExtractStep
4
-
@@ -1,125 +0,0 @@
1
- u = up.util
2
-
3
- class up.MotionTracker
4
-
5
- constructor: (name) ->
6
- @activeClass = "up-#{name}"
7
- @dataKey = "up-#{name}-finished"
8
- @selector = ".#{@activeClass}"
9
- @finishEvent = "up:#{name}:finish"
10
- @finishCount = 0
11
- @clusterCount = 0
12
-
13
- ###**
14
- Finishes all animations in the given element cluster's ancestors and descendants,
15
- then calls the animator.
16
-
17
- The animation returned by the animator is tracked so it can be
18
- [`finished`](/up.MotionTracker.finish) later.
19
-
20
- @method claim
21
- @param {jQuery} $cluster
22
- @param {Function(jQuery): Promise} animator
23
- @param {Object} memory.trackMotion = true
24
- Whether
25
- @return {Promise} A promise that is fulfilled when the new animation ends.
26
- ###
27
- claim: (cluster, animator, memory = {}) =>
28
- $cluster = $(cluster)
29
- memory.trackMotion = u.option(memory.trackMotion, up.motion.isEnabled())
30
- if memory.trackMotion is false
31
- # Since we don't want recursive tracking or finishing, we could run
32
- # the animator() now. However, since the else branch is async, we push
33
- # the animator into the microtask queue to be async as well.
34
- u.microtask(animator)
35
- else
36
- memory.trackMotion = false
37
- @finish($cluster).then =>
38
- promise = @whileForwardingFinishEvent($cluster, animator)
39
- promise = promise.then => @unmarkCluster($cluster)
40
- # Attach the modified promise to the cluster's elements
41
- @markCluster($cluster, promise)
42
- promise
43
-
44
- ###**
45
- @method finish
46
- @param {jQuery} [elements]
47
- If no element is given, finishes all animations in the documnet.
48
- If an element is given, only finishes animations in its subtree and ancestors.
49
- @return {Promise} A promise that is fulfilled when animations have finished.
50
- ###
51
- finish: (elements) =>
52
- @finishCount++
53
- return Promise.resolve() if @clusterCount == 0 || !up.motion.isEnabled()
54
- $elements = @expandFinishRequest(elements)
55
- allFinished = u.map($elements, @finishOneElement)
56
- Promise.all(allFinished)
57
-
58
- expandFinishRequest: (elements) =>
59
- if elements
60
- u.selectInDynasty($(elements), @selector)
61
- else
62
- $(@selector)
63
-
64
- isActive: (element) =>
65
- u.hasClass(element, @activeClass)
66
-
67
- finishOneElement: (element) =>
68
- $element = $(element)
69
-
70
- # Animating code is expected to listen to this event, fast-forward
71
- # the animation and resolve their promise. All built-ins like
72
- # `up.animate`, `up.morph`, or `up.scroll` behave that way.
73
- @emitFinishEvent($element)
74
-
75
- # If animating code ignores the event, we cannot force the animation to
76
- # finish from here. We will wait for the animation to end naturally before
77
- # starting the next animation.
78
- @whenElementFinished($element)
79
-
80
- emitFinishEvent: ($element, eventAttrs = {}) =>
81
- eventAttrs = u.merge({ $element: $element, message: false }, eventAttrs)
82
- up.emit(@finishEvent, eventAttrs)
83
-
84
- whenElementFinished: ($element) =>
85
- # There are some cases related to element ghosting where an element
86
- # has the class, but not the data value. In that case simply return
87
- # a resolved promise.
88
- $element.data(@dataKey) || Promise.resolve()
89
-
90
- markCluster: ($cluster, promise) =>
91
- @clusterCount++
92
- $cluster.addClass(@activeClass)
93
- $cluster.data(@dataKey, promise)
94
-
95
- unmarkCluster: ($cluster) =>
96
- @clusterCount--
97
- $cluster.removeClass(@activeClass)
98
- $cluster.removeData(@dataKey)
99
-
100
- forwardFinishEvent: ($original, $ghost, duration) =>
101
- @start $original, =>
102
- doForward = => $ghost.trigger(@finishEvent)
103
- # Forward the finish event to the $ghost that is actually animating
104
- $original.on @finishEvent, doForward
105
- # Our own pseudo-animation finishes when the actual animation on $ghost finishes
106
- duration.then => $original.off @finishEvent, doForward
107
-
108
- whileForwardingFinishEvent: ($elements, fn) =>
109
- return fn() if $elements.length < 2
110
- doForward = (event) =>
111
- unless event.forwarded
112
- u.each $elements, (element) =>
113
- $element = $(element)
114
- if element != event.target && @isActive($element)
115
- @emitFinishEvent($element, forwarded: true)
116
-
117
- # Forward the finish event to the $ghost that is actually animating
118
- $elements.on @finishEvent, doForward
119
- # Our own pseudo-animation finishes when the actual animation on $ghost finishes
120
- fn().then => $elements.off @finishEvent, doForward
121
-
122
- reset: =>
123
- @finish().then =>
124
- @finishCount = 0
125
- @clusterCount = 0
@@ -1,522 +0,0 @@
1
- ###**
2
- Request parameters
3
- ==================
4
-
5
- Methods like [`up.replace()`](/up.replace) accept request parameters (or form data values) as a `{ params }` option.
6
-
7
- This module offers a consistent API to read and manipulate request parameters independent of their type.
8
-
9
-
10
- \#\#\# Supported parameter types
11
-
12
- The following types of parameters are supported:
13
-
14
- 1. an object like `{ email: 'foo@bar.com' }`
15
- 2. a [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object
16
- 3. a query string like `email=foo%40bar.com`
17
- 4. an array of `{ name, value }` objects like `[{ name: 'email', value: 'foo@bar.com' }]`
18
-
19
- @class up.params
20
- ###
21
- up.params = (($) ->
22
- u = up.util
23
-
24
- NATURE_MISSING = 0
25
- NATURE_ARRAY = 1
26
- NATURE_QUERY = 2
27
- NATURE_FORM_DATA = 3
28
- NATURE_OBJECT = 4
29
-
30
- natureOf = (params) ->
31
- if u.isMissing(params)
32
- NATURE_MISSING
33
- else if u.isArray(params)
34
- NATURE_ARRAY
35
- else if u.isString(params)
36
- NATURE_QUERY
37
- else if u.isFormData(params)
38
- NATURE_FORM_DATA
39
- else if u.isObject(params)
40
- NATURE_OBJECT
41
- else
42
- up.fail("Unsupport params type: %o", params)
43
-
44
- ###**
45
- Returns an array representation of the given `params`.
46
-
47
- The given params value may be of any [supported type](/up.params).
48
-
49
- Each element in the returned array is an object with `{ name }` and `{ value }` properties.
50
-
51
- \#\#\# Example
52
-
53
- var array = up.params.toArray('foo=bar&baz=bam')
54
-
55
- // array is now: [
56
- // { name: 'foo', value: 'bar' },
57
- // { name: 'baz', value: 'bam' },
58
- // ]
59
-
60
- @function up.params.toArray
61
- @param {Object|FormData|string|Array|undefined} params
62
- the params to convert
63
- @return {Array}
64
- an array representation of the given params
65
- @experimental
66
- ###
67
- toArray = (params) ->
68
- switch natureOf(params)
69
- when NATURE_MISSING
70
- []
71
- when NATURE_ARRAY
72
- params
73
- when NATURE_QUERY
74
- buildArrayFromQuery(params)
75
- when NATURE_FORM_DATA
76
- buildArrayFromFormData(params)
77
- when NATURE_OBJECT
78
- buildArrayFromObject(params)
79
-
80
- ###**
81
- Returns an object representation of the given `params`.
82
-
83
- The given params value may be of any [supported type](/up.params).
84
-
85
- The returned value is a simple JavaScript object whose properties correspond
86
- to the key/values in the given `params`.
87
-
88
- \#\#\# Example
89
-
90
- var object = up.params.toObject('foo=bar&baz=bam')
91
-
92
- // object is now: {
93
- // foo: 'bar',
94
- // baz: 'bam'
95
- // ]
96
-
97
- @function up.params.toObject
98
- @param {Object|FormData|string|Array|undefined} params
99
- the params to convert
100
- @return {Array}
101
- an object representation of the given params
102
- @experimental
103
- ###
104
- toObject = (params) ->
105
- switch natureOf(params)
106
- when NATURE_MISSING
107
- {}
108
- when NATURE_ARRAY, NATURE_QUERY, NATURE_FORM_DATA
109
- buildObjectFromArray(toArray(params))
110
- when NATURE_OBJECT
111
- params
112
-
113
- ###**
114
- Returns [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) representation of the given `params`.
115
-
116
- The given params value may be of any [supported type](/up.params).
117
-
118
- \#\#\# Example
119
-
120
- var formData = up.params.toFormData('foo=bar&baz=bam')
121
-
122
- formData.get('foo') // 'bar'
123
- formData.get('baz') // 'bam'
124
-
125
- @function up.params.toFormData
126
- @param {Object|FormData|string|Array|undefined} params
127
- the params to convert
128
- @return {FormData}
129
- a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) representation of the given params
130
- @experimental
131
- ###
132
- toFormData = (params) ->
133
- switch natureOf(params)
134
- when NATURE_MISSING
135
- # Return an empty FormData object
136
- new FormData()
137
- when NATURE_ARRAY, NATURE_QUERY, NATURE_OBJECT
138
- buildFormDataFromArray(toArray(params))
139
- when NATURE_FORM_DATA
140
- params
141
-
142
- ###**
143
- Returns an query string for the given `params`.
144
-
145
- The given params value may be of any [supported type](/up.params).
146
-
147
- The keys and values in the returned query string will be [percent-encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding).
148
- Non-primitive values (like [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) will be omitted from
149
- the retuned query string.
150
-
151
- \#\#\# Example
152
-
153
- var query = up.params.toQuery({ foo: 'bar', baz: 'bam' })
154
-
155
- // query is now: 'foo=bar&baz=bam'
156
-
157
- @function up.params.toQuery
158
- @param {Object|FormData|string|Array|undefined} params
159
- the params to convert
160
- @return {string}
161
- a query string built from the given params
162
- @experimental
163
- ###
164
- toQuery = (params) ->
165
- switch natureOf(params)
166
- when NATURE_MISSING
167
- ''
168
- when NATURE_QUERY
169
- params
170
- when NATURE_ARRAY, NATURE_FORM_DATA, NATURE_OBJECT
171
- buildQueryFromArray(toArray(params))
172
-
173
- arrayEntryToQuery = (entry) ->
174
- value = entry.value
175
- return undefined unless isPrimitiveValue(value)
176
- query = encodeURIComponent(entry.name)
177
- # There is a subtle difference when encoding blank values:
178
- # 1. An undefined or null value is encoded to `key` with no equals sign
179
- # 2. An empty string value is encoded to `key=` with an equals sign but no value
180
- if u.isGiven(value)
181
- query += "="
182
- query += encodeURIComponent(value)
183
- query
184
-
185
- ###**
186
- Returns whether the given value can be encoded into a query string.
187
-
188
- We will have `File` values in our params when we serialize a form with a file input.
189
- These entries will be filtered out when converting to a query string.
190
- ###
191
- isPrimitiveValue = (value) ->
192
- u.isMissing(value) || u.isString(value) || u.isNumber(value) || u.isBoolean(value)
193
-
194
- safeSet = (obj, k, value) ->
195
- obj[k] = value unless u.isBasicObjectProperty(k)
196
-
197
- safeGet = (obj, k) ->
198
- obj[k] unless u.isBasicObjectProperty(k)
199
-
200
- buildQueryFromArray = (array) ->
201
- parts = u.map(array, arrayEntryToQuery)
202
- parts = u.compact(parts)
203
- parts.join('&')
204
-
205
- buildArrayFromQuery = (query) ->
206
- array = []
207
- for part in query.split('&')
208
- if part
209
- [name, value] = part.split('=')
210
- name = decodeURIComponent(name)
211
- # There are three forms we need to handle:
212
- # (1) foo=bar should become { name: 'foo', bar: 'bar' }
213
- # (2) foo= should become { name: 'foo', bar: '' }
214
- # (3) foo should become { name: 'foo', bar: null }
215
- if u.isGiven(value)
216
- value = decodeURIComponent(value)
217
- else
218
- value = null
219
- array.push({ name, value })
220
- array
221
-
222
- buildArrayFromObject = (object) ->
223
- array = []
224
- for k, v of object
225
- array.push(name: k, value: v)
226
- array
227
-
228
- buildObjectFromArray = (array) ->
229
- obj = {}
230
- for entry in array
231
- safeSet(obj, entry.name, entry.value)
232
- obj
233
-
234
- buildArrayFromFormData = (formData) ->
235
- array = []
236
- u.eachIterator formData.entries(), (value) ->
237
- [name, value] = value
238
- array.push({ name, value })
239
- array
240
-
241
- buildFormDataFromArray = (array) ->
242
- formData = new FormData()
243
- for entry in array
244
- formData.append(entry.name, entry.value)
245
- <% if ENV['JS_KNIFE'] %>formData.originalArray = array<% end %>
246
- formData
247
-
248
- buildURL = (base, params) ->
249
- parts = [base, toQuery(params)]
250
- parts = u.select(parts, u.isPresent)
251
- separator = if u.contains(base, '?') then '&' else '?'
252
- parts.join(separator)
253
-
254
- ###**
255
- Adds to the given `params` a new entry with the given `name` and `value`.
256
-
257
- The given params value may be of any [supported type](/up.params).
258
-
259
- The given `params` value is changed in-place, if possible. Some types, such as query strings,
260
- cannot be changed in-place. The return value is always a params value that includes the new entry.
261
-
262
- \#\#\# Example
263
-
264
- var obj = { foo: 'bar' }
265
- up.params.add(obj, 'baz', 'bam')
266
- // obj is now: { foo: 'bar', baz: 'bam' }
267
-
268
- @function up.params.add
269
- @param {string|object|FormData|Array|undefined} params
270
- @param {string} name
271
- @param {any} value
272
- @return {string|object|FormData|Array}
273
- @experimental
274
- ###
275
- add = (params, name, value) ->
276
- newEntry = [{ name, value }]
277
- assign(params, newEntry)
278
-
279
- ###**
280
- Returns a new params value that contains entries from both `params` and `otherParams`.
281
-
282
- The given params value may be of any [supported type](/up.params).
283
-
284
- This function creates a new params value. The given `params` argument is not changed.
285
-
286
- @function up.params.merge
287
- @param {string|object|FormData|Array|undefined} params
288
- @param {string|object|FormData|Array|undefined} otherParams
289
- @return {string|object|FormData|Array}
290
- @experimental
291
- ###
292
- merge = (params, otherParams) ->
293
- switch natureOf(params)
294
- when NATURE_MISSING
295
- merge({}, otherParams)
296
- when NATURE_ARRAY
297
- otherArray = toArray(otherParams)
298
- params.concat(otherArray)
299
- when NATURE_FORM_DATA
300
- formData = new FormData()
301
- assign(formData, params)
302
- assign(formData, otherParams)
303
- formData
304
- when NATURE_QUERY
305
- otherQuery = toQuery(otherParams)
306
- parts = u.select([params, otherQuery], u.isPresent)
307
- parts.join('&')
308
- when NATURE_OBJECT
309
- u.merge(params, toObject(otherParams))
310
-
311
- ###**
312
- Returns the first param value with the given `name` from the given `params`.
313
-
314
- The given params value may be of any [supported type](/up.params).
315
-
316
- \#\#\# Example
317
-
318
- var array = [
319
- { name: 'foo', value: 'bar' },
320
- { name: 'baz', value: 'bam' }
321
- }
322
-
323
- value = up.params.get(array, 'baz')
324
- // value is now: 'bam'
325
-
326
- @function up.params.get
327
- @experimental
328
- ###
329
- get = (params, name) ->
330
- switch natureOf(params)
331
- when NATURE_MISSING
332
- undefined
333
- when NATURE_ARRAY
334
- entry = u.detect(params, (entry) -> entry.name == name)
335
- entry?.value
336
- when NATURE_FORM_DATA
337
- value = params.get(name)
338
- value = undefined if u.isNull(value)
339
- value
340
- when NATURE_QUERY
341
- safeGet(toObject(params), name)
342
- when NATURE_OBJECT
343
- safeGet(params, name)
344
-
345
- ###**
346
- Extends the given `params` with entries from the given `otherParams`.
347
-
348
- The given params value may be of any [supported type](/up.params).
349
-
350
- The given `params` is changed in-place, if possible. Some types, such as query strings,
351
- cannot be changed in-place. The return value is always a params value that includes the new entries.
352
-
353
- @function up.params.assign
354
- @param {string|object|FormData|Array|undefined} params
355
- @param {string|object|FormData|Array|undefined} otherParams
356
- @return {string|object|FormData|Array}
357
- @experimental
358
- ###
359
- assign = (params, otherParams) ->
360
- switch natureOf(params)
361
- when NATURE_ARRAY
362
- otherArray = toArray(otherParams)
363
- params.push(otherArray...)
364
- params
365
- when NATURE_FORM_DATA
366
- otherArray = toArray(otherParams)
367
- for entry in otherArray
368
- params.append(entry.name, entry.value)
369
- params
370
- when NATURE_OBJECT
371
- u.assign(params, toObject(otherParams))
372
- when NATURE_QUERY, NATURE_MISSING
373
- # Strings and undefined are immutable, so we merge instead.
374
- merge(params, otherParams)
375
-
376
- submittingButton = (form) ->
377
- $form = $(form)
378
- submitButtonSelector = up.form.submitButtonSelector()
379
- $activeElement = $(document.activeElement)
380
- if $activeElement.is(submitButtonSelector) && $form.has($activeElement)
381
- $activeElement[0]
382
- else
383
- # If no button is focused, we assume the first button in the form.
384
- $form.find(submitButtonSelector)[0]
385
-
386
- ###**
387
- Serializes request params from the given `<form>`.
388
-
389
- The returned params may be passed as `{ params }` option to
390
- [`up.request()`](/up.request) or [`up.replace()`](/up.replace).
391
-
392
- The serialized params will include the form's submit button, if that
393
- button as a `name` attribute.
394
-
395
- \#\#\#\# Example
396
-
397
- Given this HTML form:
398
-
399
- <form>
400
- <input type="text" name="name" value="Foo Bar">
401
- <input type="text" name="email" value="foo@bar.com">
402
- </form>
403
-
404
- This would serialize the form into an array representation:
405
-
406
- var params = up.params.fromForm('input[name=email]')
407
-
408
- // params is now: [
409
- // { name: 'name', value: 'Foo Bar' },
410
- // { name: 'email', value: 'foo@bar.com' }
411
- // ]
412
-
413
- @function up.params.fromForm
414
- @param {Element|jQuery|string} form
415
- @return {Array}
416
- @experimental
417
- ###
418
- fromForm = (form) ->
419
- if form = u.element(form)
420
- fields = form.querySelectorAll(up.form.fieldSelector())
421
- if button = submittingButton(form)
422
- fields = u.toArray(fields)
423
- fields.push(button)
424
- return u.flatMap(fields, fromField)
425
-
426
- ###**
427
- Serializes request params from a single [input field](/up.form.config#config.fields).
428
- To serialize an entire form, use [`up.params.fromForm()`](/up.params.fromForm).
429
-
430
- Note that some fields may produce multiple params, such as `<select multiple>`.
431
-
432
- \#\#\#\# Example
433
-
434
- Given this HTML form:
435
-
436
- <form>
437
- <input type="text" name="email" value="foo@bar.com">
438
- <input type="password" name="password">
439
- </form>
440
-
441
- This would retrieve request parameters from the `email` field:
442
-
443
- var params = up.params.fromField('input[name=email]')
444
-
445
- // params is now: [{ name: 'email', value: 'foo@bar.com' }]
446
-
447
- @function up.params.fromField
448
- @param {Element|jQuery|string} form
449
- @return {Array}
450
- an array of `{ name, value }` objects
451
- @experimental
452
- ###
453
- fromField = (field) ->
454
- params = []
455
- if (field = u.element(field)) && (name = field.name) && (!field.disabled)
456
- tagName = field.tagName
457
- type = field.type
458
- if tagName == 'SELECT'
459
- for option in field.querySelectorAll('option')
460
- if option.selected
461
- params.push
462
- name: name
463
- value: option.value
464
- else if type == 'checkbox' || type == 'radio'
465
- if field.checked
466
- params.push
467
- name: name
468
- value: field.value
469
- else if type == 'file'
470
- # The value of an input[type=file] is the local path displayed in the form.
471
- # The actual File objects are in the #files property.
472
- for file in field.files
473
- params.push
474
- name: name
475
- value: file
476
- else
477
- params.push
478
- name: name
479
- value: field.value
480
- params
481
-
482
- ###**
483
- Returns the [query string](https://en.wikipedia.org/wiki/Query_string) from the given URL.
484
-
485
- The query string is returned **without** a leading question mark (`?`).
486
- Returns `undefined` if the given URL has no query component.
487
-
488
- You can access individual values from the returned query string using functions like
489
- [`up.params.get()`](/up.params.get) or [`up.params.toObject()`](/up.params.toObject).
490
-
491
- \#\#\# Example
492
-
493
- var query = up.params.fromURL('http://foo.com?bar=baz')
494
-
495
- // query is now: 'bar=baz'
496
-
497
- @function up.params.fromURL
498
- @param {string} url
499
- The URL from which to extract the query string.
500
- @return {string|undefined}
501
- The given URL's query string, or `undefined` if the URL has no query component.
502
- @experimental
503
- ###
504
- fromURL = (url) ->
505
- urlParts = u.parseUrl(url)
506
- if query = urlParts.search
507
- query = query.replace(/^\?/, '')
508
- query
509
-
510
- toArray: toArray
511
- toObject: toObject
512
- toQuery: toQuery
513
- toFormData: toFormData
514
- buildURL: buildURL
515
- get: get
516
- add: add
517
- assign: assign
518
- merge: merge
519
- fromForm: fromForm
520
- fromURL: fromURL
521
-
522
- )(jQuery)