upjs-rails 0.12.5 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rdoc_options +23 -0
- data/CHANGELOG.md +20 -0
- data/design/up-validate.js.coffee +284 -0
- data/dist/up-bootstrap.js +4 -0
- data/dist/up-bootstrap.min.js +1 -1
- data/dist/up.js +547 -102
- data/dist/up.min.js +2 -2
- data/lib/assets/javascripts/up/browser.js.coffee +3 -2
- data/lib/assets/javascripts/up/flow.js.coffee +95 -17
- data/lib/assets/javascripts/up/form.js.coffee +327 -34
- data/lib/assets/javascripts/up/history.js.coffee +1 -1
- data/lib/assets/javascripts/up/layout.js.coffee +4 -4
- data/lib/assets/javascripts/up/link.js.coffee +5 -2
- data/lib/assets/javascripts/up/modal.js.coffee +1 -0
- data/lib/assets/javascripts/up/proxy.js.coffee +27 -12
- data/lib/assets/javascripts/up/syntax.js.coffee +39 -20
- data/lib/assets/javascripts/up/util.js.coffee +29 -12
- data/lib/assets/javascripts/up-bootstrap/form-ext.js.coffee +1 -0
- data/lib/upjs/rails/engine.rb +1 -1
- data/lib/upjs/rails/inspector.rb +63 -0
- data/lib/upjs/rails/inspector_accessor.rb +28 -0
- data/lib/upjs/rails/request_echo_headers.rb +7 -0
- data/lib/upjs/rails/request_method_cookie.rb +12 -4
- data/lib/upjs/rails/version.rb +5 -1
- data/lib/upjs-rails.rb +7 -5
- data/spec_app/.rspec +2 -0
- data/spec_app/Gemfile +0 -3
- data/spec_app/Gemfile.lock +43 -44
- data/spec_app/app/assets/stylesheets/application.css +1 -1
- data/spec_app/app/controllers/test_controller.rb +23 -0
- data/spec_app/config/routes.rb +2 -0
- data/spec_app/spec/controllers/test_controller_spec.rb +67 -0
- data/spec_app/spec/javascripts/helpers/append_fixture.js.coffee +8 -0
- data/spec_app/spec/javascripts/helpers/last_request.js.coffee +18 -0
- data/spec_app/spec/javascripts/helpers/reset_path.js.coffee +1 -0
- data/spec_app/spec/javascripts/up/flow_spec.js.coffee +93 -43
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +80 -18
- data/spec_app/spec/javascripts/up/history_spec.js.coffee +1 -5
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +18 -17
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +32 -37
- data/spec_app/spec/javascripts/up/navigation_spec.js.coffee +7 -26
- data/spec_app/spec/javascripts/up/popup_spec.js.coffee +1 -7
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +26 -25
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +23 -0
- data/spec_app/spec/spec_helper.rb +62 -0
- metadata +12 -3
- data/lib/upjs/rails/request_ext.rb +0 -13
@@ -1,21 +1,10 @@
|
|
1
1
|
###*
|
2
|
-
Forms
|
3
|
-
|
2
|
+
Forms
|
3
|
+
=====
|
4
4
|
|
5
|
-
Up.js comes with functionality to submit
|
6
|
-
leaving the current page. This means you can replace page fragments,
|
5
|
+
Up.js comes with functionality to [submit](/form-up-target) and [validate](/up-validate)
|
6
|
+
forms without leaving the current page. This means you can replace page fragments,
|
7
7
|
open dialogs with sub-forms, etc. all without losing form state.
|
8
|
-
|
9
|
-
\#\#\# Incomplete documentation!
|
10
|
-
|
11
|
-
We need to work on this page:
|
12
|
-
|
13
|
-
- Explain how to display form errors
|
14
|
-
- Explain that the server needs to send 2xx or 5xx status codes so
|
15
|
-
Up.js can decide whether the form submission was successful
|
16
|
-
- Explain that the server needs to send `X-Up-Location` and `X-Up-Method` headers
|
17
|
-
if an successful form submission resulted in a redirect
|
18
|
-
- Examples
|
19
8
|
|
20
9
|
@class up.form
|
21
10
|
###
|
@@ -24,14 +13,37 @@ up.form = (($) ->
|
|
24
13
|
u = up.util
|
25
14
|
|
26
15
|
###*
|
27
|
-
|
28
|
-
|
29
|
-
|
16
|
+
Sets default options for form submission and validation.
|
17
|
+
|
18
|
+
@property up.form.config
|
19
|
+
@param {Array} [config.validateTargets=['[up-fieldset]:has(&)', 'fieldset:has(&)', 'label:has(&)', 'form:has(&)']]
|
20
|
+
An array of CSS selectors that are searched around a form field
|
21
|
+
that wants to [validate](/up.validate). The first matching selector
|
22
|
+
will be updated with the validation messages from the server.
|
23
|
+
|
24
|
+
By default this looks for a `<fieldset>`, `<label>` or `<form>`
|
25
|
+
around the validating input field, or any element with an
|
26
|
+
`up-fieldset` attribute.
|
27
|
+
###
|
28
|
+
config = u.config
|
29
|
+
validateTargets: ['[up-fieldset]:has(&)', 'fieldset:has(&)', 'label:has(&)', 'form:has(&)']
|
30
|
+
|
31
|
+
reset = ->
|
32
|
+
config.reset()
|
33
|
+
|
34
|
+
###*
|
35
|
+
Submits a form via AJAX and updates a page fragment with the response.
|
36
|
+
|
37
|
+
up.submit('form.new-user', { target: '.main' })
|
30
38
|
|
31
39
|
Instead of loading a new page, the form is submitted via AJAX.
|
32
40
|
The response is parsed for a CSS selector and the matching elements will
|
33
41
|
replace corresponding elements on the current page.
|
34
|
-
|
42
|
+
|
43
|
+
The UJS variant of this is the [`form[up-target]`](/form-up-target) selector.
|
44
|
+
See the documentation for [`form[up-target]`](/form-up-target) for more
|
45
|
+
information on how AJAX form submissions work in Up.js.
|
46
|
+
|
35
47
|
@function up.submit
|
36
48
|
@param {Element|jQuery|String} formOrSelector
|
37
49
|
A reference or selector for the form to submit.
|
@@ -81,6 +93,9 @@ up.form = (($) ->
|
|
81
93
|
|
82
94
|
By default only responses to `GET` requests are cached
|
83
95
|
for a few minutes.
|
96
|
+
@param {Object} [options.headers={}]
|
97
|
+
An object of additional header key/value pairs to send along
|
98
|
+
with the request.
|
84
99
|
@return {Promise}
|
85
100
|
A promise for the successful form submission.
|
86
101
|
###
|
@@ -89,27 +104,38 @@ up.form = (($) ->
|
|
89
104
|
$form = $(formOrSelector).closest('form')
|
90
105
|
|
91
106
|
options = u.options(options)
|
92
|
-
successSelector = u.option(options.target, $form.attr('up-target'), 'body')
|
93
|
-
failureSelector = u.option(options.failTarget, $form.attr('up-fail-target'), -> u.createSelectorFromElement($form))
|
107
|
+
successSelector = up.flow.resolveSelector(u.option(options.target, $form.attr('up-target'), 'body'), options)
|
108
|
+
failureSelector = up.flow.resolveSelector(u.option(options.failTarget, $form.attr('up-fail-target'), -> u.createSelectorFromElement($form)), options)
|
94
109
|
historyOption = u.option(options.history, u.castedAttr($form, 'up-history'), true)
|
95
110
|
successTransition = u.option(options.transition, u.castedAttr($form, 'up-transition'))
|
96
111
|
failureTransition = u.option(options.failTransition, u.castedAttr($form, 'up-fail-transition'), successTransition)
|
97
112
|
httpMethod = u.option(options.method, $form.attr('up-method'), $form.attr('data-method'), $form.attr('method'), 'post').toUpperCase()
|
113
|
+
headers = u.option(options.headers, {})
|
98
114
|
|
99
115
|
implantOptions = {}
|
100
116
|
implantOptions.reveal = u.option(options.reveal, u.castedAttr($form, 'up-reveal'), true)
|
101
117
|
implantOptions.cache = u.option(options.cache, u.castedAttr($form, 'up-cache'))
|
102
118
|
implantOptions.restoreScroll = u.option(options.restoreScroll, u.castedAttr($form, 'up-restore-scroll'))
|
119
|
+
implantOptions.origin = u.option(options.origin, $form)
|
103
120
|
implantOptions = u.extend(implantOptions, up.motion.animateOptions(options, $form))
|
104
121
|
|
105
122
|
useCache = u.option(options.cache, u.castedAttr($form, 'up-cache'))
|
106
123
|
url = u.option(options.url, $form.attr('action'), up.browser.url())
|
107
|
-
|
124
|
+
|
125
|
+
hasFileInputs = $form.find('input[type=file]').length
|
126
|
+
|
127
|
+
if options.validate
|
128
|
+
headers['X-Up-Validate'] = options.validate
|
129
|
+
# Since we cannot (yet) submit file inputs via AJAX, we cannot
|
130
|
+
# offer inline validation for such forms.
|
131
|
+
if hasFileInputs
|
132
|
+
return u.unresolvablePromise()
|
133
|
+
|
108
134
|
$form.addClass('up-active')
|
109
|
-
|
110
|
-
if !up.browser.canPushState() && historyOption != false
|
135
|
+
|
136
|
+
if hasFileInputs || (!up.browser.canPushState() && historyOption != false)
|
111
137
|
$form.get(0).submit()
|
112
|
-
return
|
138
|
+
return u.unresolvablePromise()
|
113
139
|
|
114
140
|
request = {
|
115
141
|
url: url
|
@@ -117,6 +143,7 @@ up.form = (($) ->
|
|
117
143
|
data: $form.serialize()
|
118
144
|
selector: successSelector
|
119
145
|
cache: useCache
|
146
|
+
headers: headers
|
120
147
|
}
|
121
148
|
|
122
149
|
successUrl = (xhr) ->
|
@@ -148,7 +175,11 @@ up.form = (($) ->
|
|
148
175
|
Observes a form field and runs a callback when its value changes.
|
149
176
|
This is useful for observing text fields while the user is typing.
|
150
177
|
|
151
|
-
|
178
|
+
The UJS variant of this is the [`up-observe`](/up-observe) attribute.
|
179
|
+
|
180
|
+
\#\#\#\# Example
|
181
|
+
|
182
|
+
The following would submit the form whenever the
|
152
183
|
text field value changes:
|
153
184
|
|
154
185
|
up.observe('input[name=query]', { change: function(value, $input) {
|
@@ -176,7 +207,6 @@ up.form = (($) ->
|
|
176
207
|
change: function(value, $input) { up.submit($input) }
|
177
208
|
});
|
178
209
|
|
179
|
-
|
180
210
|
@function up.observe
|
181
211
|
@param {Element|jQuery|String} fieldOrSelector
|
182
212
|
@param {Function(value, $field)|String} options.change
|
@@ -265,14 +295,125 @@ up.form = (($) ->
|
|
265
295
|
# return destructor
|
266
296
|
return clearTimer
|
267
297
|
|
298
|
+
resolveValidateTarget = ($field, options) ->
|
299
|
+
target = u.option(options.target, $field.attr('up-validate'))
|
300
|
+
if u.isBlank(target)
|
301
|
+
target ||= u.detect(config.validateTargets, (defaultTarget) ->
|
302
|
+
resolvedDefault = up.flow.resolveSelector(defaultTarget, options)
|
303
|
+
$field.closest(resolvedDefault).length
|
304
|
+
)
|
305
|
+
if u.isBlank(target)
|
306
|
+
error('Could not find default validation target for %o (tried ancestors %o)', $field, config.validateTargets)
|
307
|
+
unless u.isString(target)
|
308
|
+
target = u.createSelectorFromElement(target)
|
309
|
+
target
|
310
|
+
|
311
|
+
###*
|
312
|
+
Performs a server-side validation of a form and update the form
|
313
|
+
with validation messages.
|
314
|
+
|
315
|
+
`up.validate` submits the given field's form with an additional `X-Up-Validate`
|
316
|
+
HTTP header. Upon seeing this header, the server is expected to validate (but not save)
|
317
|
+
the form submission and render a new copy of the form with validation errors.
|
318
|
+
|
319
|
+
The UJS variant of this is the [`[up-validate]`](/up-validate) selector.
|
320
|
+
See the documentation for [`[up-validate]`](/up-validate) for more information
|
321
|
+
on how server-side validation works in Up.js.
|
322
|
+
|
323
|
+
\#\#\#\# Example
|
324
|
+
|
325
|
+
up.validate('input[name=email]', { target: '.email-errors' })
|
326
|
+
|
327
|
+
@function up.validate
|
328
|
+
@param {String|Element|jQuery} fieldOrSelector
|
329
|
+
@param {String|Element|jQuery} [options.target]
|
330
|
+
@return {Promise}
|
331
|
+
A promise that is resolved when the server-side
|
332
|
+
validation is received and the form was updated.
|
333
|
+
###
|
334
|
+
validate = (fieldOrSelector, options) ->
|
335
|
+
$field = $(fieldOrSelector)
|
336
|
+
options = u.options(options)
|
337
|
+
options.origin = $field
|
338
|
+
options.target = resolveValidateTarget($field, options)
|
339
|
+
options.failTarget = options.target
|
340
|
+
options.history = false
|
341
|
+
options.headers = u.option(options.headers, {})
|
342
|
+
# Make sure the X-Up-Validate header is present, so the server-side
|
343
|
+
# knows that it should not persist the form submission
|
344
|
+
options.validate = ($field.attr('name') || '__none__')
|
345
|
+
options = u.merge(options, up.motion.animateOptions(options, $field))
|
346
|
+
$form = $field.closest('form')
|
347
|
+
promise = up.submit($form, options)
|
348
|
+
promise
|
349
|
+
|
268
350
|
###*
|
269
|
-
|
270
|
-
|
351
|
+
Forms with an `up-target` attribute are [submitted via AJAX](/up.submit)
|
352
|
+
instead of triggering a full page reload.
|
271
353
|
|
272
354
|
<form method="post" action="/users" up-target=".main">
|
273
355
|
...
|
274
356
|
</form>
|
275
357
|
|
358
|
+
The server response is searched for the selector given in `up-target`.
|
359
|
+
The selector content is then [replaced](/up.replace) in the current page.
|
360
|
+
|
361
|
+
The programmatic variant of this is the [`up.submit`](/up.submit) function.
|
362
|
+
|
363
|
+
\#\#\#\# Validation errors
|
364
|
+
|
365
|
+
When the server was unable to save the form due to invalid data,
|
366
|
+
it will usually re-render an updated copy of the form with
|
367
|
+
validation messages.
|
368
|
+
|
369
|
+
For Up.js to be able to pick up a validation failure,
|
370
|
+
the form must be re-rendered with a non-200 HTTP status code.
|
371
|
+
We recommend to use either 400 (bad request) or
|
372
|
+
422 (unprocessable entity).
|
373
|
+
|
374
|
+
In Ruby on Rails, you can pass a
|
375
|
+
[`:status` option to `render`](http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option)
|
376
|
+
for this:
|
377
|
+
|
378
|
+
class UsersController < ApplicationController
|
379
|
+
|
380
|
+
def create
|
381
|
+
user_params = params[:user].permit(:email, :password)
|
382
|
+
@user = User.new(user_params)
|
383
|
+
if @user.save?
|
384
|
+
sign_in @user
|
385
|
+
else
|
386
|
+
render 'form', status: :bad_request
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
end
|
391
|
+
|
392
|
+
Note that you can also use the
|
393
|
+
[`up-validate`](/up-validate) attribute to perform server-side
|
394
|
+
validations while the user is completing fields.
|
395
|
+
|
396
|
+
\#\#\#\# Redirects
|
397
|
+
|
398
|
+
Up.js requires two additional response headers to detect redirects,
|
399
|
+
which are otherwise undetectable for an AJAX client.
|
400
|
+
|
401
|
+
When the form's action performs a redirect, the server should echo
|
402
|
+
the new request's URL as a response header `X-Up-Location`
|
403
|
+
and the request's HTTP method as `X-Up-Method`.
|
404
|
+
|
405
|
+
If you are using Up.js via the `upjs-rails` gem, these headers
|
406
|
+
are set automatically for every request.
|
407
|
+
|
408
|
+
\#\#\#\# Giving feedback while the form is processing
|
409
|
+
|
410
|
+
The `<form>` element will be assigned a CSS class `up-active` while
|
411
|
+
the submission is loading.
|
412
|
+
|
413
|
+
You can also [implement a spinner](/up.proxy/#spinners)
|
414
|
+
by [listening](/up.on) to the [`up:proxy:busy`](/up:proxy:busy)
|
415
|
+
and [`up:proxy:idle`](/up:proxy:idle) events.
|
416
|
+
|
276
417
|
@selector form[up-target]
|
277
418
|
@param {String} up-target
|
278
419
|
The selector to [replace](/up.replace) if the form submission is successful (200 status code).
|
@@ -306,11 +447,160 @@ up.form = (($) ->
|
|
306
447
|
event.preventDefault()
|
307
448
|
submit($form)
|
308
449
|
|
450
|
+
###*
|
451
|
+
When a form field with this attribute is changed,
|
452
|
+
the form is validated on the server and is updated with
|
453
|
+
validation messages.
|
454
|
+
|
455
|
+
The programmatic variant of this is the [`up.validate`](/up.validate) function.
|
456
|
+
|
457
|
+
\#\#\#\# Example
|
458
|
+
|
459
|
+
Let's look at a standard registration form that asks for an e-mail and password:
|
460
|
+
|
461
|
+
<form action="/users">
|
462
|
+
|
463
|
+
<label>
|
464
|
+
E-mail: <input type="text" name="email" />
|
465
|
+
</label>
|
466
|
+
|
467
|
+
<label>
|
468
|
+
Password: <input type="password" name="password" />
|
469
|
+
</label>
|
470
|
+
|
471
|
+
<button type="submit">Register</button>
|
472
|
+
|
473
|
+
</form>
|
474
|
+
|
475
|
+
When the user changes the `email` field, we want to validate that
|
476
|
+
the e-mail address is valid and still available. Also we want to
|
477
|
+
change the `password` field for the minimum required password length.
|
478
|
+
We can do this by giving both fields an `up-validate` attribute:
|
479
|
+
|
480
|
+
<form action="/users">
|
481
|
+
|
482
|
+
<label>
|
483
|
+
E-mail: <input type="text" name="email" up-validate />
|
484
|
+
</label>
|
485
|
+
|
486
|
+
<label>
|
487
|
+
Password: <input type="password" name="password" up-validate />
|
488
|
+
</label>
|
489
|
+
|
490
|
+
<button type="submit">Register</button>
|
491
|
+
|
492
|
+
</form>
|
493
|
+
|
494
|
+
Whenever a field with `up-validate` changes, the form is POSTed to
|
495
|
+
`/users` with an additional `X-Up-Validate` HTTP header.
|
496
|
+
Upon seeing this header, the server is expected to validate (but not save)
|
497
|
+
the form submission and render a new copy of the form with validation errors.
|
498
|
+
|
499
|
+
In Ruby on Rails the processing action should behave like this:
|
500
|
+
|
501
|
+
class UsersController < ApplicationController
|
502
|
+
|
503
|
+
# This action handles POST /users
|
504
|
+
def create
|
505
|
+
user_params = params[:user].permit(:email, :password)
|
506
|
+
@user = User.new(user_params)
|
507
|
+
if request.headers['X-Up-Validate']
|
508
|
+
@user.valid? # run validations, but don't save to the database
|
509
|
+
render 'form' # render form with error messages
|
510
|
+
elsif @user.save?
|
511
|
+
sign_in @user
|
512
|
+
else
|
513
|
+
render 'form', status: :bad_request
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
end
|
518
|
+
|
519
|
+
Note that if you're using the `upjs-rails` gem you can simply say `up.validate?`
|
520
|
+
instead of manually checking for `request.headers['X-Up-Validate']`.
|
521
|
+
|
522
|
+
The server now renders an updated copy of the form with eventual validation errors:
|
523
|
+
|
524
|
+
<form action="/users">
|
525
|
+
|
526
|
+
<label class="has-error">
|
527
|
+
E-mail: <input type="text" name="email" value="foo@bar.com" />
|
528
|
+
Has already been taken!
|
529
|
+
</label>
|
530
|
+
|
531
|
+
<button type="submit">Register</button>
|
532
|
+
|
533
|
+
</form>
|
534
|
+
|
535
|
+
The `<label>` around the e-mail field is now updated to have the `has-error`
|
536
|
+
class and display the validation message.
|
537
|
+
|
538
|
+
\#\#\#\# How validation results are displayed
|
539
|
+
|
540
|
+
Although the server will usually respond to a validation with a complete,
|
541
|
+
fresh copy of the form, Up.js will by default not update the entire form.
|
542
|
+
This is done in order to preserve volatile state such as the scroll position
|
543
|
+
of `<textarea>` elements.
|
544
|
+
|
545
|
+
By default Up.js looks for a `<fieldset>`, `<label>` or `<form>`
|
546
|
+
around the validating input field, or any element with an
|
547
|
+
`up-fieldset` attribute.
|
548
|
+
With the Bootstrap bindings, Up.js will also look
|
549
|
+
for a container with the `form-group` class.
|
550
|
+
|
551
|
+
You can change this default behavior by setting `up.config.validateTargets`:
|
552
|
+
|
553
|
+
// Always update the entire form containing the current field ("&")
|
554
|
+
up.config.validateTargets = ['form &']
|
555
|
+
|
556
|
+
You can also individually override what to update by setting the `up-validate`
|
557
|
+
attribute to a CSS selector:
|
558
|
+
|
559
|
+
<input type="text" name="email" up-validate=".email-errors">
|
560
|
+
<span class="email-errors"></span>
|
561
|
+
|
562
|
+
|
563
|
+
\#\#\#\# Updating dependent fields
|
564
|
+
|
565
|
+
The `[up-validate]` behavior is also a great way to partially update a form
|
566
|
+
when one fields depends on the value of another field.
|
567
|
+
|
568
|
+
Let's say you have a form with one `<select>` to pick a department (sales, engineering, ...)
|
569
|
+
and another `<select>` to pick an employeee from the selected department:
|
570
|
+
|
571
|
+
<form action="/contracts">
|
572
|
+
<select name="department">...</select> <!-- options for all departments -->
|
573
|
+
<select name="employeed">...</select> <!-- options for employees of selected department -->
|
574
|
+
</form>
|
575
|
+
|
576
|
+
The list of employees needs to be updated as the appartment changes:
|
577
|
+
|
578
|
+
<form action="/contracts">
|
579
|
+
<select name="department" up-validate="[name=employee]">...</select>
|
580
|
+
<select name="employee">...</select>
|
581
|
+
</form>
|
582
|
+
|
583
|
+
In order to update the `department` field in addition to the `employee` field, you could say
|
584
|
+
`up-validate="&, [name=employee]"`, or simply `up-validate="form"` to update the entire form.
|
585
|
+
|
586
|
+
@selector [up-validate]
|
587
|
+
@param {String} up-validate
|
588
|
+
The CSS selector to update with the server response.
|
589
|
+
|
590
|
+
This defaults to a fieldset or form group around the validating field.
|
591
|
+
###
|
592
|
+
up.on 'change', '[up-validate]', (event, $field) ->
|
593
|
+
validate($field)
|
594
|
+
|
309
595
|
###*
|
310
596
|
Observes this form field and runs the given script
|
311
597
|
when its value changes. This is useful for observing text fields
|
312
598
|
while the user is typing.
|
313
599
|
|
600
|
+
The programmatic variant of this is the [`up.observe`](/up.observe) function.
|
601
|
+
|
602
|
+
\#\#\#\# Example
|
603
|
+
|
314
604
|
For instance, the following would submit the form whenever the
|
315
605
|
text field value changes:
|
316
606
|
|
@@ -318,7 +608,7 @@ up.form = (($) ->
|
|
318
608
|
<input type="query" up-observe="up.form.submit(this)">
|
319
609
|
</form>
|
320
610
|
|
321
|
-
The script given
|
611
|
+
The script given to `up-observe` runs with the following context:
|
322
612
|
|
323
613
|
| Name | Type | Description |
|
324
614
|
| -------- | --------- | ------------------------------------- |
|
@@ -326,11 +616,9 @@ up.form = (($) ->
|
|
326
616
|
| `this` | `Element` | The form field |
|
327
617
|
| `$field` | `jQuery` | The form field as a jQuery collection |
|
328
618
|
|
329
|
-
|
330
|
-
|
331
|
-
@selector input[up-observe]
|
332
|
-
The code to run when the field's value changes.
|
619
|
+
@selector [up-observe]
|
333
620
|
@param {String} up-observe
|
621
|
+
The code to run when the field's value changes.
|
334
622
|
###
|
335
623
|
up.compiler '[up-observe]', ($field) ->
|
336
624
|
return observe($field)
|
@@ -343,10 +631,15 @@ up.form = (($) ->
|
|
343
631
|
# $field.removeClass('up-active')
|
344
632
|
# )
|
345
633
|
|
634
|
+
up.on 'up:framework:reset', reset
|
635
|
+
|
346
636
|
submit: submit
|
347
637
|
observe: observe
|
638
|
+
validate: validate
|
348
639
|
|
349
640
|
)(jQuery)
|
350
641
|
|
351
642
|
up.submit = up.form.submit
|
352
643
|
up.observe = up.form.observe
|
644
|
+
up.validate = up.form.validate
|
645
|
+
|
@@ -18,7 +18,7 @@ up.history = (($) ->
|
|
18
18
|
|
19
19
|
###*
|
20
20
|
@property up.history.config
|
21
|
-
@param {Array
|
21
|
+
@param {Array} [config.popTargets=['body']]
|
22
22
|
An array of CSS selectors to replace when the user goes
|
23
23
|
back in history.
|
24
24
|
@param {Boolean} [config.restoreScroll=true]
|
@@ -14,16 +14,16 @@ up.layout = (($) ->
|
|
14
14
|
Configures the application layout.
|
15
15
|
|
16
16
|
@property up.layout.config
|
17
|
-
@param {Array
|
17
|
+
@param {Array} [config.viewports]
|
18
18
|
An array of CSS selectors that find viewports
|
19
19
|
(containers that scroll their contents).
|
20
|
-
@param {Array
|
20
|
+
@param {Array} [config.fixedTop]
|
21
21
|
An array of CSS selectors that find elements fixed to the
|
22
22
|
top edge of the screen (using `position: fixed`).
|
23
|
-
@param {Array
|
23
|
+
@param {Array} [config.fixedBottom]
|
24
24
|
An array of CSS selectors that find elements fixed to the
|
25
25
|
bottom edge of the screen (using `position: fixed`).
|
26
|
-
@param {Array
|
26
|
+
@param {Array} [config.anchoredRight]
|
27
27
|
An array of CSS selectors that find elements anchored to the
|
28
28
|
right edge of the screen (using `position: fixed` or `position: absolute`).
|
29
29
|
@param {Number} [config.duration]
|
@@ -140,12 +140,15 @@ up.link = (($) ->
|
|
140
140
|
@param {Element|jQuery|String} [options.reveal]
|
141
141
|
Whether to reveal the target element within its viewport before updating.
|
142
142
|
@param {Boolean} [options.restoreScroll]
|
143
|
-
If set to `true`, this will attempt to [
|
143
|
+
If set to `true`, this will attempt to [restore scroll positions](/up.restoreScroll)
|
144
144
|
previously seen on the destination URL.
|
145
145
|
@param {Boolean} [options.cache]
|
146
146
|
Whether to force the use of a cached response (`true`)
|
147
147
|
or never use the cache (`false`)
|
148
148
|
or make an educated guess (`undefined`).
|
149
|
+
@param {Object} [options.headers={}]
|
150
|
+
An object of additional header key/value pairs to send along
|
151
|
+
with the request.
|
149
152
|
###
|
150
153
|
follow = (linkOrSelector, options) ->
|
151
154
|
$link = $(linkOrSelector)
|
@@ -159,6 +162,7 @@ up.link = (($) ->
|
|
159
162
|
options.cache = u.option(options.cache, u.castedAttr($link, 'up-cache'))
|
160
163
|
options.restoreScroll = u.option(options.restoreScroll, u.castedAttr($link, 'up-restore-scroll'))
|
161
164
|
options.method = followMethod($link, options)
|
165
|
+
options.origin = u.option(options.origin, $link)
|
162
166
|
options = u.merge(options, up.motion.animateOptions(options, $link))
|
163
167
|
|
164
168
|
up.replace(selector, url, options)
|
@@ -371,7 +375,6 @@ up.link = (($) ->
|
|
371
375
|
$area.removeAttr('up-expand')
|
372
376
|
makeFollowable($area)
|
373
377
|
|
374
|
-
|
375
378
|
###*
|
376
379
|
Marks up the current link to be followed *as fast as possible*.
|
377
380
|
This is done by:
|
@@ -452,6 +452,7 @@ up.modal = (($) ->
|
|
452
452
|
# The framework is reset between tests
|
453
453
|
up.on 'up:framework:reset', reset
|
454
454
|
|
455
|
+
knife: eval(Knife?.point)
|
455
456
|
visit: visit
|
456
457
|
follow: follow
|
457
458
|
open: -> up.error('up.modal.open no longer exists. Please use either up.modal.follow or up.modal.visit.')
|
@@ -75,7 +75,7 @@ up.proxy = (($) ->
|
|
75
75
|
The number of milliseconds until a cache entry expires.
|
76
76
|
Defaults to 5 minutes.
|
77
77
|
@param {Number} [config.busyDelay=300]
|
78
|
-
How long the proxy waits until emitting the `proxy:busy`
|
78
|
+
How long the proxy waits until emitting the [`up:proxy:busy` event](/up:proxy:busy).
|
79
79
|
Use this to prevent flickering of spinners.
|
80
80
|
###
|
81
81
|
config = u.config
|
@@ -98,11 +98,23 @@ up.proxy = (($) ->
|
|
98
98
|
key: cacheKey
|
99
99
|
log: 'up.proxy'
|
100
100
|
|
101
|
+
|
101
102
|
###*
|
102
103
|
@protected
|
103
104
|
@function up.proxy.get
|
104
105
|
###
|
105
|
-
get =
|
106
|
+
get = (request) ->
|
107
|
+
request = normalizeRequest(request)
|
108
|
+
candidates = [request]
|
109
|
+
unless request.selector is 'html'
|
110
|
+
requestForHtml = u.merge(request, selector: 'html')
|
111
|
+
candidates.push(requestForHtml)
|
112
|
+
unless request.selector is 'body'
|
113
|
+
requestForBody = u.merge(request, selector: 'body')
|
114
|
+
candidates.push(requestForBody)
|
115
|
+
for candidate in candidates
|
116
|
+
if response = cache.get(candidate)
|
117
|
+
return response
|
106
118
|
|
107
119
|
###*
|
108
120
|
@protected
|
@@ -162,8 +174,8 @@ up.proxy = (($) ->
|
|
162
174
|
are considered to be read-only.
|
163
175
|
|
164
176
|
If a network connection is attempted, the proxy will emit
|
165
|
-
a `proxy:load` event with the `request` as its argument.
|
166
|
-
Once the response is received, a `proxy:receive` event will
|
177
|
+
a `up:proxy:load` event with the `request` as its argument.
|
178
|
+
Once the response is received, a `up:proxy:receive` event will
|
167
179
|
be emitted.
|
168
180
|
|
169
181
|
@function up.proxy.ajax
|
@@ -173,13 +185,16 @@ up.proxy = (($) ->
|
|
173
185
|
@param {Boolean} [request.cache]
|
174
186
|
Whether to use a cached response, if available.
|
175
187
|
If set to `false` a network connection will always be attempted.
|
188
|
+
@param {Object} [request.headers={}]
|
189
|
+
An object of additional header key/value pairs to send along
|
190
|
+
with the request.
|
176
191
|
###
|
177
192
|
ajax = (options) ->
|
178
193
|
|
179
194
|
forceCache = (options.cache == true)
|
180
195
|
ignoreCache = (options.cache == false)
|
181
196
|
|
182
|
-
request = u.only(options, 'url', 'method', 'data', 'selector', '_normalized')
|
197
|
+
request = u.only(options, 'url', 'method', 'data', 'selector', 'headers', '_normalized')
|
183
198
|
|
184
199
|
pending = true
|
185
200
|
|
@@ -204,11 +219,11 @@ up.proxy = (($) ->
|
|
204
219
|
# following case:
|
205
220
|
#
|
206
221
|
# - User starts preloading a request.
|
207
|
-
# This triggers *no* `proxy:busy`.
|
222
|
+
# This triggers *no* `up:proxy:busy`.
|
208
223
|
# - User starts loading the request (without preloading).
|
209
|
-
# This triggers `proxy:busy`.
|
224
|
+
# This triggers `up:proxy:busy`.
|
210
225
|
# - The request finishes.
|
211
|
-
# This triggers `proxy:idle`.
|
226
|
+
# This triggers `up:proxy:idle`.
|
212
227
|
loadStarted()
|
213
228
|
promise.always(loadEnded)
|
214
229
|
|
@@ -220,7 +235,7 @@ up.proxy = (($) ->
|
|
220
235
|
Returns `true` if the proxy is not currently waiting
|
221
236
|
for a request to finish. Returns `false` otherwise.
|
222
237
|
|
223
|
-
The proxy will also emit an `proxy:idle`
|
238
|
+
The proxy will also emit an [`up:proxy:idle` event](/up:proxy:idle) if it
|
224
239
|
used to busy, but is now idle.
|
225
240
|
|
226
241
|
@function up.proxy.idle
|
@@ -233,8 +248,8 @@ up.proxy = (($) ->
|
|
233
248
|
Returns `true` if the proxy is currently waiting
|
234
249
|
for a request to finish. Returns `false` otherwise.
|
235
250
|
|
236
|
-
The proxy will also emit an `proxy:busy`
|
237
|
-
used to idle, but is now busy.
|
251
|
+
The proxy will also emit an [`up:proxy:busy` event](/up:proxy:busy) if it
|
252
|
+
used to be idle, but is now busy.
|
238
253
|
|
239
254
|
@function up.proxy.busy
|
240
255
|
@return {Boolean} Whether the proxy is busy
|
@@ -285,7 +300,7 @@ up.proxy = (($) ->
|
|
285
300
|
This event is [emitted]/(up.emit) when [AJAX requests](/up.proxy.ajax)
|
286
301
|
have [taken long to finish](/up:proxy:busy), but have finished now.
|
287
302
|
|
288
|
-
@event up:proxy:
|
303
|
+
@event up:proxy:idle
|
289
304
|
###
|
290
305
|
|
291
306
|
load = (request) ->
|