upjs-rails 0.12.5 → 0.13.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.
- 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) ->
|