unpoly-rails 0.57.0 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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)