unpoly-rails 0.56.7 → 0.57.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -1
- data/dist/unpoly.js +1569 -793
- data/dist/unpoly.min.js +4 -4
- data/lib/assets/javascripts/unpoly.coffee +2 -0
- data/lib/assets/javascripts/unpoly/browser.coffee.erb +25 -41
- data/lib/assets/javascripts/unpoly/bus.coffee.erb +20 -6
- data/lib/assets/javascripts/unpoly/classes/cache.coffee +23 -13
- data/lib/assets/javascripts/unpoly/classes/compile_pass.coffee +87 -0
- data/lib/assets/javascripts/unpoly/classes/focus_tracker.coffee +29 -0
- data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +7 -4
- data/lib/assets/javascripts/unpoly/classes/record.coffee +1 -1
- data/lib/assets/javascripts/unpoly/classes/request.coffee +38 -45
- data/lib/assets/javascripts/unpoly/classes/response.coffee +16 -1
- data/lib/assets/javascripts/unpoly/classes/store/memory.coffee +26 -0
- data/lib/assets/javascripts/unpoly/classes/store/session.coffee +59 -0
- data/lib/assets/javascripts/unpoly/cookie.coffee +56 -0
- data/lib/assets/javascripts/unpoly/dom.coffee.erb +67 -39
- data/lib/assets/javascripts/unpoly/feedback.coffee +2 -2
- data/lib/assets/javascripts/unpoly/form.coffee.erb +23 -12
- data/lib/assets/javascripts/unpoly/history.coffee +2 -2
- data/lib/assets/javascripts/unpoly/layout.coffee.erb +118 -99
- data/lib/assets/javascripts/unpoly/link.coffee.erb +12 -5
- data/lib/assets/javascripts/unpoly/log.coffee +6 -5
- data/lib/assets/javascripts/unpoly/modal.coffee.erb +9 -2
- data/lib/assets/javascripts/unpoly/motion.coffee.erb +2 -6
- data/lib/assets/javascripts/unpoly/namespace.coffee.erb +2 -2
- data/lib/assets/javascripts/unpoly/params.coffee.erb +522 -0
- data/lib/assets/javascripts/unpoly/popup.coffee.erb +3 -3
- data/lib/assets/javascripts/unpoly/proxy.coffee +42 -34
- data/lib/assets/javascripts/unpoly/{syntax.coffee → syntax.coffee.erb} +59 -117
- data/lib/assets/javascripts/unpoly/{util.coffee → util.coffee.erb} +206 -171
- data/lib/unpoly/rails/version.rb +1 -1
- data/package.json +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/app/assets/javascripts/integration_test.coffee +0 -4
- data/spec_app/app/assets/stylesheets/integration_test.sass +7 -1
- data/spec_app/app/controllers/pages_controller.rb +4 -0
- data/spec_app/app/views/form_test/basics/new.erb +34 -5
- data/spec_app/app/views/form_test/submission_result.erb +2 -2
- data/spec_app/app/views/form_test/uploads/new.erb +15 -2
- data/spec_app/app/views/hash_test/unpoly.erb +30 -0
- data/spec_app/app/views/pages/start.erb +2 -1
- data/spec_app/spec/javascripts/helpers/parse_form_data.js.coffee +17 -2
- data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +5 -0
- data/spec_app/spec/javascripts/helpers/to_be_error.coffee +1 -1
- data/spec_app/spec/javascripts/helpers/to_match_selector.coffee +5 -0
- data/spec_app/spec/javascripts/up/browser_spec.js.coffee +8 -8
- data/spec_app/spec/javascripts/up/bus_spec.js.coffee +58 -20
- data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +78 -0
- data/spec_app/spec/javascripts/up/classes/focus_tracker_spec.coffee +31 -0
- data/spec_app/spec/javascripts/up/classes/request_spec.coffee +50 -0
- data/spec_app/spec/javascripts/up/classes/store/memory_spec.js.coffee +67 -0
- data/spec_app/spec/javascripts/up/classes/store/session_spec.js.coffee +113 -0
- data/spec_app/spec/javascripts/up/dom_spec.js.coffee +133 -45
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +13 -13
- data/spec_app/spec/javascripts/up/layout_spec.js.coffee +110 -26
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +1 -1
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +1 -0
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +52 -51
- data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +2 -2
- data/spec_app/spec/javascripts/up/params_spec.coffee +768 -0
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +75 -36
- data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +48 -15
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +148 -131
- metadata +17 -5
- data/spec_app/spec/javascripts/up/classes/.keep +0 -0
@@ -122,8 +122,13 @@ up.link = (($) ->
|
|
122
122
|
An element or selector which is either an `<a>` tag or any element with an `up-href` attribute.
|
123
123
|
@param {string} [options.target]
|
124
124
|
The selector to replace.
|
125
|
-
|
125
|
+
|
126
|
+
Defaults to the link's `[up-target]`, `[up-modal]` or `[up-popup]` attribute.
|
126
127
|
If no target is given, the `<body>` element will be replaced.
|
128
|
+
@param {String} [options.url]
|
129
|
+
The URL to navigate to.
|
130
|
+
|
131
|
+
Defaults to the link's `[up-href]` or `[href]` attribute.
|
127
132
|
@param {boolean|string} [options.reveal=true]
|
128
133
|
Whether to [reveal](/up.reveal) the target fragment after it was replaced.
|
129
134
|
|
@@ -145,8 +150,10 @@ up.link = (($) ->
|
|
145
150
|
###**
|
146
151
|
This event is [emitted](/up.emit) when a link is [followed](/up.follow) through Unpoly.
|
147
152
|
|
153
|
+
The event is emitted on the `<a>` element that is being followed.
|
154
|
+
|
148
155
|
@event up:link:follow
|
149
|
-
@param {jQuery} event.$
|
156
|
+
@param {jQuery} event.$link
|
150
157
|
The link element that will be followed.
|
151
158
|
@param event.preventDefault()
|
152
159
|
Event listeners may call this method to prevent the link from being followed.
|
@@ -162,7 +169,7 @@ up.link = (($) ->
|
|
162
169
|
|
163
170
|
options = u.options(options)
|
164
171
|
|
165
|
-
url = u.option($link.attr('up-href'), $link.attr('href'))
|
172
|
+
url = u.option(options.url, $link.attr('up-href'), $link.attr('href'))
|
166
173
|
target = u.option(options.target, $link.attr('up-target'))
|
167
174
|
options.failTarget = u.option(options.failTarget, $link.attr('up-fail-target'))
|
168
175
|
options.fallback = u.option(options.fallback, $link.attr('up-fallback'))
|
@@ -396,9 +403,9 @@ up.link = (($) ->
|
|
396
403
|
or make an educated guess (default).
|
397
404
|
@param {string} [up-layer='auto']
|
398
405
|
The name of the layer that ought to be updated. Valid values are
|
399
|
-
`auto`, `page`, `modal` and `popup`.
|
406
|
+
`'auto'`, `'page'`, `'modal'` and `'popup'`.
|
400
407
|
|
401
|
-
If set to `auto` (default), Unpoly will try to find a match in the link's layer.
|
408
|
+
If set to `'auto'` (default), Unpoly will try to find a match in the link's layer.
|
402
409
|
If no match was found in that layer,
|
403
410
|
Unpoly will search in other layers, starting from the topmost layer.
|
404
411
|
@param {string} [up-fail-layer='auto']
|
@@ -18,7 +18,7 @@ up.log = (($) ->
|
|
18
18
|
u = up.util
|
19
19
|
b = up.browser
|
20
20
|
|
21
|
-
|
21
|
+
sessionStore = new up.store.Session('up.log')
|
22
22
|
|
23
23
|
###**
|
24
24
|
Configures the logging output on the developer console.
|
@@ -41,7 +41,7 @@ up.log = (($) ->
|
|
41
41
|
###
|
42
42
|
config = u.config
|
43
43
|
prefix: '[UP] '
|
44
|
-
enabled:
|
44
|
+
enabled: sessionStore.get('enabled')
|
45
45
|
collapse: false
|
46
46
|
|
47
47
|
reset = ->
|
@@ -75,7 +75,7 @@ up.log = (($) ->
|
|
75
75
|
b.puts('log', prefix(message), args...)
|
76
76
|
|
77
77
|
###**
|
78
|
-
@function up.
|
78
|
+
@function up.warn
|
79
79
|
@internal
|
80
80
|
###
|
81
81
|
warn = (message, args...) ->
|
@@ -126,8 +126,7 @@ up.log = (($) ->
|
|
126
126
|
up.on 'up:framework:reset', reset
|
127
127
|
|
128
128
|
setEnabled = (value) ->
|
129
|
-
|
130
|
-
b.sessionStorage().setItem(SESSION_KEY_ENABLED, value.toString())
|
129
|
+
sessionStore.set('enabled', value)
|
131
130
|
config.enabled = value
|
132
131
|
|
133
132
|
###**
|
@@ -165,3 +164,5 @@ up.log = (($) ->
|
|
165
164
|
)(jQuery)
|
166
165
|
|
167
166
|
up.puts = up.log.puts
|
167
|
+
up.warn = up.log.warn
|
168
|
+
|
@@ -439,7 +439,8 @@ up.modal = (($) ->
|
|
439
439
|
$link = u.option(u.pluckKey(options, '$link'), u.nullJQuery())
|
440
440
|
url = u.option(u.pluckKey(options, 'url'), $link.attr('up-href'), $link.attr('href'))
|
441
441
|
html = u.option(u.pluckKey(options, 'html'))
|
442
|
-
target = u.option(u.pluckKey(options, 'target'), $link.attr('up-modal')
|
442
|
+
target = u.option(u.pluckKey(options, 'target'), $link.attr('up-modal'))
|
443
|
+
validateTarget(target)
|
443
444
|
options.flavor = u.option(options.flavor, $link.attr('up-flavor'), config.flavor)
|
444
445
|
options.position = u.option(options.position, $link.attr('up-position'), flavorDefault('position', options.flavor))
|
445
446
|
options.position = u.evalOption(options.position, $link: $link)
|
@@ -497,6 +498,12 @@ up.modal = (($) ->
|
|
497
498
|
up.emit('up:modal:opened', message: 'Modal opened')
|
498
499
|
promise
|
499
500
|
|
501
|
+
validateTarget = (target) ->
|
502
|
+
if u.isBlank(target)
|
503
|
+
up.fail('Cannot open a modal without a target selector')
|
504
|
+
else if target == 'body'
|
505
|
+
up.fail('Cannot open the <body> in a modal')
|
506
|
+
|
500
507
|
###**
|
501
508
|
This event is [emitted](/up.emit) when a modal dialog is starting to open.
|
502
509
|
|
@@ -629,7 +636,7 @@ up.modal = (($) ->
|
|
629
636
|
$element.closest('.up-modal').length > 0
|
630
637
|
|
631
638
|
flavor = (name, overrideConfig = {}) ->
|
632
|
-
up.
|
639
|
+
up.warn 'up.modal.flavor() is deprecated. Use the up.modal.flavors property instead.'
|
633
640
|
u.assign(flavorOverrides(name), overrideConfig)
|
634
641
|
|
635
642
|
###**
|
@@ -176,11 +176,7 @@ up.motion = (($) ->
|
|
176
176
|
|
177
177
|
willAnimate = ($elements, animationOrTransition, options) ->
|
178
178
|
options = animateOptions(options)
|
179
|
-
isEnabled() && !isNone(animationOrTransition) && options.duration > 0 && !isSingletonElement($elements)
|
180
|
-
|
181
|
-
isSingletonElement = ($element) ->
|
182
|
-
# jQuery's is() returns true if at least one element in the collection matches the selector
|
183
|
-
$element.is('body')
|
179
|
+
isEnabled() && !isNone(animationOrTransition) && options.duration > 0 && !u.isSingletonElement($elements)
|
184
180
|
|
185
181
|
skipAnimate = ($element, animation) ->
|
186
182
|
if u.isOptions(animation)
|
@@ -355,7 +351,7 @@ up.motion = (($) ->
|
|
355
351
|
# Don't animate the scrolling. The { duration } option was meant for the transition.
|
356
352
|
scrollOptions = u.merge(options, duration: 0)
|
357
353
|
# Scroll $new into position before we start the enter animation.
|
358
|
-
up.layout.
|
354
|
+
up.layout.scrollAfterInsertFragment($new, scrollOptions)
|
359
355
|
|
360
356
|
if willMorph
|
361
357
|
if motionTracker.isActive($old) && options.trackMotion is false
|
@@ -4,7 +4,7 @@
|
|
4
4
|
window.up =
|
5
5
|
version: <%= Unpoly::Rails::VERSION.to_json %>
|
6
6
|
|
7
|
-
|
7
|
+
deprecateRenamedModule: (oldName, newName) ->
|
8
8
|
Object.defineProperty? up, oldName, get: ->
|
9
|
-
up.
|
9
|
+
up.warn("Deprecated: up.#{oldName} has been renamed to up.#{newName}")
|
10
10
|
up[newName]
|
@@ -0,0 +1,522 @@
|
|
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)
|