unpoly-rails 0.33.0 → 0.34.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of unpoly-rails might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README_RAILS.md +3 -3
- data/dist/unpoly.js +382 -97
- data/dist/unpoly.min.js +3 -3
- data/lib/assets/javascripts/unpoly.coffee +1 -0
- data/lib/assets/javascripts/unpoly/browser.coffee +37 -18
- data/lib/assets/javascripts/unpoly/bus.coffee +5 -6
- data/lib/assets/javascripts/unpoly/dom.coffee +11 -5
- data/lib/assets/javascripts/unpoly/form.coffee +5 -6
- data/lib/assets/javascripts/unpoly/history.coffee +18 -10
- data/lib/assets/javascripts/unpoly/layout.coffee +40 -9
- data/lib/assets/javascripts/unpoly/protocol.coffee +235 -0
- data/lib/assets/javascripts/unpoly/proxy.coffee +3 -6
- data/lib/assets/javascripts/unpoly/syntax.coffee +2 -2
- data/lib/assets/javascripts/unpoly/util.coffee +0 -24
- data/lib/assets/stylesheets/unpoly/{flow.sass → dom.sass} +0 -0
- data/lib/unpoly/rails/request_method_cookie.rb +4 -4
- data/lib/unpoly/rails/version.rb +1 -1
- data/package.json +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/spec/controllers/binding_test_controller_spec.rb +46 -0
- data/spec_app/spec/javascripts/up/layout_spec.js.coffee +30 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 513b5201d93ee8e087b990e708f6c0c3fae07d59
|
4
|
+
data.tar.gz: 0034f1a7a0e17e1f43d2a33d9783a831fc338880
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a75fc96dee7eac045e62627ea82aec8509106d45e29a3d884fad95257be227aecaa42ed6983a6142fc45aa9b633f017b6ffd77bd73111a5b434c5ea00d6d676
|
7
|
+
data.tar.gz: 1815f021f9da6e10e087a5c68eacf7c7f841787af52175afa88ad599b29ef3c6de45762a9a6572c3f773ac2b097e4e9566cf757198276f85d5846cb1064602fc
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,31 @@ All notable changes to this project will be documented in this file.
|
|
6
6
|
This project mostly adheres to [Semantic Versioning](http://semver.org/).
|
7
7
|
|
8
8
|
|
9
|
+
0.34.0
|
10
|
+
------
|
11
|
+
|
12
|
+
### Compatible changes
|
13
|
+
|
14
|
+
- During the initial page load Unpoly now [reveals](/up.reveal) an element matching the
|
15
|
+
`#hash` in the current URL.
|
16
|
+
|
17
|
+
Other than the default behavior found in browsers, `up.revealHash` works with
|
18
|
+
[multiple viewports](/up-viewport) and honors [fixed elements](/up-fixed-top) obstructing the user's
|
19
|
+
view of the viewport.
|
20
|
+
- New experimental function [`up.layout.revealHash()`](/up.layout.revealHash).
|
21
|
+
- The optional server protocol is now [documented](/up.protocol).
|
22
|
+
The protocol is already implemented by the [`unpoly-rails`](https://rubygems.org/gems/unpoly-rails) Ruby gem.
|
23
|
+
- New experimental property [`up.protocol.config`](/up.protocol.config)
|
24
|
+
- [`up.browser.isSupported()`](/up.browser.isSupported) has been promoted from experimental to stable API
|
25
|
+
|
26
|
+
|
27
|
+
### Breaking changes
|
28
|
+
|
29
|
+
- `up.proxy.config.wrapMethodParam` is now [`up.protocol.config.methodParam`](/up.protocol.config#config.methodParam).
|
30
|
+
- The event [`up:history:restored`](/up:history:restored) is no longer emitted when a history state
|
31
|
+
was not created by Unpoly.
|
32
|
+
|
33
|
+
|
9
34
|
0.33.0
|
10
35
|
------
|
11
36
|
|
data/README_RAILS.md
CHANGED
@@ -11,11 +11,11 @@ The methods documented below are available in all controllers, views and helpers
|
|
11
11
|
|
12
12
|
### Detecting a fragment update
|
13
13
|
|
14
|
-
To test whether the current request is a [fragment update](http://unpoly.com/up.
|
14
|
+
To test whether the current request is a [fragment update](http://unpoly.com/up.link):
|
15
15
|
|
16
16
|
up?
|
17
17
|
|
18
|
-
To retrieve the CSS selector that is being [updated](http://unpoly.com/up.
|
18
|
+
To retrieve the CSS selector that is being [updated](http://unpoly.com/up.link):
|
19
19
|
|
20
20
|
up.target
|
21
21
|
|
@@ -70,7 +70,7 @@ The Unpoly frontend [requires these headers to detect redirects](http://unpoly.c
|
|
70
70
|
|
71
71
|
### Automatic method detection for initial page load
|
72
72
|
|
73
|
-
`unpoly-rails` sets an `
|
73
|
+
`unpoly-rails` sets an `_up_method` cookie that Unpoly needs to detect the request method for the initial page load.
|
74
74
|
|
75
75
|
If the initial page was loaded with a non-`GET` HTTP method, Unpoly will fall back to full page loads for all actions that require `pushState`.
|
76
76
|
|
data/dist/unpoly.js
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
(function() {
|
7
7
|
this.up = {
|
8
|
-
version: "0.
|
8
|
+
version: "0.34.0",
|
9
9
|
renamedModule: function(oldName, newName) {
|
10
10
|
return typeof Object.defineProperty === "function" ? Object.defineProperty(up, oldName, {
|
11
11
|
get: function() {
|
@@ -41,7 +41,7 @@ that might save you from loading something like [Underscore.js](http://underscor
|
|
41
41
|
@function up.util.noop
|
42
42
|
@experimental
|
43
43
|
*/
|
44
|
-
var $createElementFromSelector, $createPlaceholder, ANIMATION_DEFERRED_KEY, DivertibleChain, ESCAPE_HTML_ENTITY_MAP, all, any, appendRequestData, assign, assignPolyfill, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detachWith, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, evalOption, except, extractOptions, fail, findWithSelf, finishCssAnimate, fixedToAbsolute, flatten, forceCompositing, forceRepaint, horizontalScreenHalf, identity, intersect, isArray, isBlank, isDeferred, isDefined, isDetached, isElement, isFixed, isFormData, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isNumber, isObject, isPresent, isPromise, isResolvedPromise, isStandardPort, isString, isTruthy, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, last,
|
44
|
+
var $createElementFromSelector, $createPlaceholder, ANIMATION_DEFERRED_KEY, DivertibleChain, ESCAPE_HTML_ENTITY_MAP, all, any, appendRequestData, assign, assignPolyfill, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detachWith, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, evalOption, except, extractOptions, fail, findWithSelf, finishCssAnimate, fixedToAbsolute, flatten, forceCompositing, forceRepaint, horizontalScreenHalf, identity, intersect, isArray, isBlank, isDeferred, isDefined, isDetached, isElement, isFixed, isFormData, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isNumber, isObject, isPresent, isPromise, isResolvedPromise, isStandardPort, isString, isTruthy, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, last, map, margins, measure, memoize, merge, multiSelector, nextFrame, nonUpClasses, noop, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, opacity, openConfig, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, promiseTimer, reject, rejectedPromise, remove, requestDataAsArray, requestDataAsQuery, requestDataFromForm, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, sequence, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, whenReady;
|
45
45
|
noop = $.noop;
|
46
46
|
|
47
47
|
/**
|
@@ -1366,30 +1366,6 @@ that might save you from loading something like [Underscore.js](http://underscor
|
|
1366
1366
|
}
|
1367
1367
|
};
|
1368
1368
|
|
1369
|
-
/**
|
1370
|
-
@function up.util.locationFromXhr
|
1371
|
-
@internal
|
1372
|
-
*/
|
1373
|
-
locationFromXhr = function(xhr) {
|
1374
|
-
return xhr.getResponseHeader('X-Up-Location');
|
1375
|
-
};
|
1376
|
-
|
1377
|
-
/**
|
1378
|
-
@function up.util.titleFromXhr
|
1379
|
-
@internal
|
1380
|
-
*/
|
1381
|
-
titleFromXhr = function(xhr) {
|
1382
|
-
return xhr.getResponseHeader('X-Up-Title');
|
1383
|
-
};
|
1384
|
-
|
1385
|
-
/**
|
1386
|
-
@function up.util.methodFromXhr
|
1387
|
-
@internal
|
1388
|
-
*/
|
1389
|
-
methodFromXhr = function(xhr) {
|
1390
|
-
return xhr.getResponseHeader('X-Up-Method');
|
1391
|
-
};
|
1392
|
-
|
1393
1369
|
/**
|
1394
1370
|
Returns a copy of the given object that only contains
|
1395
1371
|
the given properties.
|
@@ -2463,9 +2439,6 @@ that might save you from loading something like [Underscore.js](http://underscor
|
|
2463
2439
|
contains: contains,
|
2464
2440
|
toArray: toArray,
|
2465
2441
|
castedAttr: castedAttr,
|
2466
|
-
locationFromXhr: locationFromXhr,
|
2467
|
-
titleFromXhr: titleFromXhr,
|
2468
|
-
methodFromXhr: methodFromXhr,
|
2469
2442
|
clientSize: clientSize,
|
2470
2443
|
only: only,
|
2471
2444
|
except: except,
|
@@ -2513,6 +2486,244 @@ that might save you from loading something like [Underscore.js](http://underscor
|
|
2513
2486
|
|
2514
2487
|
}).call(this);
|
2515
2488
|
|
2489
|
+
/**
|
2490
|
+
Server protocol
|
2491
|
+
===============
|
2492
|
+
|
2493
|
+
You rarely need to change server-side code
|
2494
|
+
in order to use Unpoly. There is no need to provide a JSON API, or add
|
2495
|
+
extra routes for AJAX requests. The server simply renders a series
|
2496
|
+
of full HTML pages, just like it would without Unpoly.
|
2497
|
+
|
2498
|
+
That said, there is an **optional** protocol your server can use to
|
2499
|
+
exchange additional information when Unpoly is [updating fragments](/up.link).
|
2500
|
+
|
2501
|
+
While the protocol can help you optimize performance and handle some
|
2502
|
+
edge cases, implementing it is entirely optional. For instance,
|
2503
|
+
`unpoly.com` itself is a static site that uses Unpoly on the frontend
|
2504
|
+
and doesn't even have a server component.
|
2505
|
+
|
2506
|
+
If you have [installed Unpoly as a Rails gem](/install/rails), the protocol
|
2507
|
+
is already implemented and you will get some
|
2508
|
+
[Ruby bindings](https://github.com/unpoly/unpoly/blob/master/README_RAILS.md)
|
2509
|
+
in your controllers and views. If your server-side app uses another language
|
2510
|
+
or framework, you should be able to implement the protocol in a very short time.
|
2511
|
+
|
2512
|
+
|
2513
|
+
\#\#\# Redirect detection
|
2514
|
+
|
2515
|
+
Unpoly requires an additional response header to detect redirects, which are
|
2516
|
+
otherwise undetectable for any AJAX client.
|
2517
|
+
|
2518
|
+
After the form's action performs a redirect, the next response should include the new
|
2519
|
+
URL in this HTTP header:
|
2520
|
+
|
2521
|
+
```http
|
2522
|
+
X-Up-Location: /current-url
|
2523
|
+
```
|
2524
|
+
|
2525
|
+
The **simplest implementation** is to set this header for every request.
|
2526
|
+
|
2527
|
+
|
2528
|
+
\#\#\# Optimizing responses
|
2529
|
+
|
2530
|
+
When [updating a fragment](http://unpoly.com/up.link), Unpoly will send
|
2531
|
+
an additional HTTP header containing the CSS selector that is being replaced:
|
2532
|
+
|
2533
|
+
```http
|
2534
|
+
X-Up-Target: .user-list
|
2535
|
+
```
|
2536
|
+
|
2537
|
+
Server-side code is free to **optimize its response** by only returning HTML
|
2538
|
+
that matches the selector. For example, you might prefer to not render an
|
2539
|
+
expensive sidebar if the sidebar is not targeted.
|
2540
|
+
|
2541
|
+
|
2542
|
+
\#\#\# Pushing a document title to the client
|
2543
|
+
|
2544
|
+
When [updating a fragment](http://unpoly.com/up.link), Unpoly will by default
|
2545
|
+
extract the `<title>` from the server response and update the document title accordingly.
|
2546
|
+
|
2547
|
+
The server can also force Unpoly to set a document title by passing a HTTP header:
|
2548
|
+
|
2549
|
+
```http
|
2550
|
+
X-Up-Title: My server-pushed title
|
2551
|
+
```
|
2552
|
+
|
2553
|
+
This is useful when you [optimize your response](#optimizing-responses) and not render
|
2554
|
+
the application layout unless it is targeted. Since your optimized response
|
2555
|
+
no longer includes a `<title>`, you can instead use the HTTP header to pass the document title.
|
2556
|
+
|
2557
|
+
|
2558
|
+
\#\#\# Signaling failed form submissions
|
2559
|
+
|
2560
|
+
When [submitting a form via AJAX](http://unpoly.com/form-up-target)
|
2561
|
+
Unpoly needs to know whether the form submission has failed (to update the form with
|
2562
|
+
validation errors) or succeeded (to update the `up-target` selector).
|
2563
|
+
|
2564
|
+
For Unpoly to be able to detect a failed form submission, the response must be
|
2565
|
+
return a non-200 HTTP status code. We recommend to use either
|
2566
|
+
400 (bad request) or 422 (unprocessable entity).
|
2567
|
+
|
2568
|
+
To do so in [Ruby on Rails](http://rubyonrails.org/), pass a [`:status` option to `render`](http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option):
|
2569
|
+
|
2570
|
+
class UsersController < ApplicationController
|
2571
|
+
|
2572
|
+
def create
|
2573
|
+
user_params = params[:user].permit(:email, :password)
|
2574
|
+
@user = User.new(user_params)
|
2575
|
+
if @user.save?
|
2576
|
+
sign_in @user
|
2577
|
+
else
|
2578
|
+
render 'form', status: :bad_request
|
2579
|
+
end
|
2580
|
+
end
|
2581
|
+
|
2582
|
+
end
|
2583
|
+
|
2584
|
+
|
2585
|
+
\#\#\# Detecting live form validations
|
2586
|
+
|
2587
|
+
When [validating a form](http://unpoly.com/up-validate), Unpoly will
|
2588
|
+
send an additional HTTP header containing a CSS selector for the form that is
|
2589
|
+
being updated:
|
2590
|
+
|
2591
|
+
```http
|
2592
|
+
X-Up-Validate: .user-form
|
2593
|
+
```
|
2594
|
+
|
2595
|
+
When detecting a validation request, the server is expected to **validate (but not save)**
|
2596
|
+
the form submission and render a new copy of the form with validation errors.
|
2597
|
+
|
2598
|
+
Below you will an example for a writing route that is aware of Unpoly's live form
|
2599
|
+
validations. The code is for [Ruby on Rails](http://rubyonrails.org/),
|
2600
|
+
but you can adapt it for other languages:
|
2601
|
+
|
2602
|
+
class UsersController < ApplicationController
|
2603
|
+
|
2604
|
+
def create
|
2605
|
+
user_params = params[:user].permit(:email, :password)
|
2606
|
+
@user = User.new(user_params)
|
2607
|
+
if request.headers['X-Up-Validate']
|
2608
|
+
@user.valid? # run validations, but don't save to the database
|
2609
|
+
render 'form' # render form with error messages
|
2610
|
+
elsif @user.save?
|
2611
|
+
sign_in @user
|
2612
|
+
else
|
2613
|
+
render 'form', status: :bad_request
|
2614
|
+
end
|
2615
|
+
end
|
2616
|
+
|
2617
|
+
end
|
2618
|
+
|
2619
|
+
|
2620
|
+
\#\#\# Signaling the initial request method
|
2621
|
+
|
2622
|
+
This is a edge case you might or might not care about:
|
2623
|
+
If the initial page was loaded with a non-`GET` HTTP method, Unpoly prefers to make a full
|
2624
|
+
page load when you try to update a fragment. Once a page was loaded with a `GET` method,
|
2625
|
+
Unpoly will restore its standard behavior.
|
2626
|
+
|
2627
|
+
The reason for this is that some browsers remember the method of the initial page load and don't let
|
2628
|
+
the application change it, even with `pushState`. Thus, when the user reloads the page much later,
|
2629
|
+
an affected browser might request a `POST`, `PUT`, etc. instead of the correct method.
|
2630
|
+
|
2631
|
+
In order to allow Unpoly to detect the HTTP method of the initial page load,
|
2632
|
+
the server must set a cookie:
|
2633
|
+
|
2634
|
+
```http
|
2635
|
+
Set-Cookie: _up_method=POST
|
2636
|
+
```
|
2637
|
+
|
2638
|
+
When Unpoly boots, it will look for this cookie and configure its behavior accordingly.
|
2639
|
+
The cookie is then deleted in order to not affect following requests.
|
2640
|
+
|
2641
|
+
The **simplest implementation** is to set this cookie for every request that is neither
|
2642
|
+
`GET` nor contains an [`X-Up-Target` header](/#optimizing-responses). For all other requests
|
2643
|
+
an existing cookie should be deleted.
|
2644
|
+
|
2645
|
+
|
2646
|
+
@class up.protocol
|
2647
|
+
*/
|
2648
|
+
|
2649
|
+
(function() {
|
2650
|
+
up.protocol = (function($) {
|
2651
|
+
var config, initialRequestMethod, locationFromXhr, methodFromXhr, titleFromXhr, u;
|
2652
|
+
u = up.util;
|
2653
|
+
|
2654
|
+
/**
|
2655
|
+
@function up.protocol.locationFromXhr
|
2656
|
+
@internal
|
2657
|
+
*/
|
2658
|
+
locationFromXhr = function(xhr) {
|
2659
|
+
return xhr.getResponseHeader(config.locationHeader);
|
2660
|
+
};
|
2661
|
+
|
2662
|
+
/**
|
2663
|
+
@function up.protocol.titleFromXhr
|
2664
|
+
@internal
|
2665
|
+
*/
|
2666
|
+
titleFromXhr = function(xhr) {
|
2667
|
+
return xhr.getResponseHeader(config.titleHeader);
|
2668
|
+
};
|
2669
|
+
|
2670
|
+
/**
|
2671
|
+
@function up.protocol.methodFromXhr
|
2672
|
+
@internal
|
2673
|
+
*/
|
2674
|
+
methodFromXhr = function(xhr) {
|
2675
|
+
return xhr.getResponseHeader(config.methodHeader);
|
2676
|
+
};
|
2677
|
+
|
2678
|
+
/**
|
2679
|
+
Server-side companion libraries like unpoly-rails set this cookie so we
|
2680
|
+
have a way to detect the request method of the initial page load.
|
2681
|
+
There is no JavaScript API for this.
|
2682
|
+
|
2683
|
+
@function up.protocol.initialRequestMethod
|
2684
|
+
@internal
|
2685
|
+
*/
|
2686
|
+
initialRequestMethod = u.memoize(function() {
|
2687
|
+
var methodFromServer;
|
2688
|
+
methodFromServer = up.browser.popCookie(config.methodCookie);
|
2689
|
+
return (methodFromServer || 'get').toLowerCase();
|
2690
|
+
});
|
2691
|
+
|
2692
|
+
/**
|
2693
|
+
Configures strings used in the optional [server protocol](/up.protocol).
|
2694
|
+
|
2695
|
+
@property up.protocol.config
|
2696
|
+
@param [config.targetHeader='X-Up-Target']
|
2697
|
+
@param [config.locationHeader='X-Up-Location']
|
2698
|
+
@param [config.titleHeader='X-Up-Title']
|
2699
|
+
@param [config.validateHeader='X-Up-Validate']
|
2700
|
+
@param [config.methodHeader='X-Up-Method']
|
2701
|
+
@param [config.methodCookie='_up_method']
|
2702
|
+
@param [config.methodParam='_method']
|
2703
|
+
The name of the POST parameter when [wrapping HTTP methods](/up.form.config#config.wrapMethods)
|
2704
|
+
in a `POST` request.
|
2705
|
+
@experimental
|
2706
|
+
*/
|
2707
|
+
config = u.config({
|
2708
|
+
targetHeader: 'X-Up-Target',
|
2709
|
+
locationHeader: 'X-Up-Location',
|
2710
|
+
validateHeader: 'X-Up-Validate',
|
2711
|
+
titleHeader: 'X-Up-Title',
|
2712
|
+
methodHeader: 'X-Up-Method',
|
2713
|
+
methodCookie: '_up_method',
|
2714
|
+
methodParam: '_method'
|
2715
|
+
});
|
2716
|
+
return {
|
2717
|
+
config: config,
|
2718
|
+
locationFromXhr: locationFromXhr,
|
2719
|
+
titleFromXhr: titleFromXhr,
|
2720
|
+
methodFromXhr: methodFromXhr,
|
2721
|
+
initialRequestMethod: initialRequestMethod
|
2722
|
+
};
|
2723
|
+
})(jQuery);
|
2724
|
+
|
2725
|
+
}).call(this);
|
2726
|
+
|
2516
2727
|
/**
|
2517
2728
|
Browser support
|
2518
2729
|
===============
|
@@ -2536,7 +2747,7 @@ IE 8
|
|
2536
2747
|
var slice = [].slice;
|
2537
2748
|
|
2538
2749
|
up.browser = (function($) {
|
2539
|
-
var CONSOLE_PLACEHOLDERS, canCssTransition, canFormData, canInputEvent, canLogSubstitution, canPushState,
|
2750
|
+
var CONSOLE_PLACEHOLDERS, canCssTransition, canFormData, canInputEvent, canLogSubstitution, canPushState, hash, installPolyfills, isIE8OrWorse, isIE9OrWorse, isRecentJQuery, isSupported, loadPage, popCookie, puts, sessionStorage, setLocationHref, sprintf, sprintfWithFormattedArgs, stringifyArg, submitForm, u, url, whenConfirmed;
|
2540
2751
|
u = up.util;
|
2541
2752
|
|
2542
2753
|
/**
|
@@ -2567,7 +2778,7 @@ IE 8
|
|
2567
2778
|
return $field.appendTo($form);
|
2568
2779
|
};
|
2569
2780
|
addField({
|
2570
|
-
name: up.
|
2781
|
+
name: up.protocol.config.methodParam,
|
2571
2782
|
value: method
|
2572
2783
|
});
|
2573
2784
|
if (csrfField = up.rails.csrfField()) {
|
@@ -2719,7 +2930,7 @@ IE 8
|
|
2719
2930
|
@experimental
|
2720
2931
|
*/
|
2721
2932
|
canPushState = u.memoize(function() {
|
2722
|
-
return u.isDefined(history.pushState) && initialRequestMethod() === 'get';
|
2933
|
+
return u.isDefined(history.pushState) && up.protocol.initialRequestMethod() === 'get';
|
2723
2934
|
});
|
2724
2935
|
|
2725
2936
|
/**
|
@@ -2785,6 +2996,14 @@ IE 8
|
|
2785
2996
|
minor = parseInt(parts[1]);
|
2786
2997
|
return major >= 2 || (major === 1 && minor >= 9);
|
2787
2998
|
});
|
2999
|
+
|
3000
|
+
/**
|
3001
|
+
Returns and deletes a cookie with the given name
|
3002
|
+
Inspired by Turbolinks: https://github.com/rails/turbolinks/blob/83d4b3d2c52a681f07900c28adb28bc8da604733/lib/assets/javascripts/turbolinks.coffee#L292
|
3003
|
+
|
3004
|
+
@function up.browser.popCookie
|
3005
|
+
@internal
|
3006
|
+
*/
|
2788
3007
|
popCookie = function(name) {
|
2789
3008
|
var ref, value;
|
2790
3009
|
value = (ref = document.cookie.match(new RegExp(name + "=(\\w+)"))) != null ? ref[1] : void 0;
|
@@ -2808,25 +3027,25 @@ IE 8
|
|
2808
3027
|
return u.unresolvablePromise();
|
2809
3028
|
}
|
2810
3029
|
};
|
2811
|
-
initialRequestMethod = u.memoize(function() {
|
2812
|
-
return (popCookie('_up_request_method') || 'get').toLowerCase();
|
2813
|
-
});
|
2814
3030
|
|
2815
3031
|
/**
|
2816
3032
|
Returns whether Unpoly supports the current browser.
|
2817
3033
|
|
2818
|
-
|
2819
|
-
gracefully for other features. E.g. IE9 is almost fully supported, but due to
|
2820
|
-
its lack of [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
|
2821
|
-
Unpoly falls back to a full page load when asked to manipulate history.
|
2822
|
-
|
2823
|
-
Currently Unpoly supports IE9 with jQuery 1.9+.
|
2824
|
-
On older browsers Unpoly will prevent itself from [booting](/up.boot)
|
3034
|
+
If this returns `false` Unpoly will prevent itself from [booting](/up.boot)
|
2825
3035
|
and ignores all registered [event handlers](/up.on) and [compilers](/up.compiler).
|
2826
3036
|
This leaves you with a classic server-side application.
|
3037
|
+
This is usually a better fallback than loading incompatible Javascript and causing
|
3038
|
+
many errors on load.
|
3039
|
+
|
3040
|
+
\#\#\# Graceful degradation
|
3041
|
+
|
3042
|
+
This function also returns `true` if Unpoly only support some features, but can degrade
|
3043
|
+
gracefully for other features. E.g. Internet Explorer 9 is almost fully supported, but due to
|
3044
|
+
its lack of [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
|
3045
|
+
Unpoly falls back to a full page load when asked to manipulate history.
|
2827
3046
|
|
2828
3047
|
@function up.browser.isSupported
|
2829
|
-
@
|
3048
|
+
@stable
|
2830
3049
|
*/
|
2831
3050
|
isSupported = function() {
|
2832
3051
|
return (!isIE8OrWorse()) && isRecentJQuery();
|
@@ -2864,6 +3083,23 @@ IE 8
|
|
2864
3083
|
removeItem: u.noop
|
2865
3084
|
};
|
2866
3085
|
});
|
3086
|
+
|
3087
|
+
/**
|
3088
|
+
Returns `'foo'` if the hash is `'#foo'`.
|
3089
|
+
|
3090
|
+
Returns undefined if the hash is `'#'`, `''` or `undefined`.
|
3091
|
+
|
3092
|
+
@function up.browser.hash
|
3093
|
+
@internal
|
3094
|
+
*/
|
3095
|
+
hash = function(value) {
|
3096
|
+
value || (value = location.hash);
|
3097
|
+
value || (value = '');
|
3098
|
+
if (value[0] === '#') {
|
3099
|
+
value = value.substr(1);
|
3100
|
+
}
|
3101
|
+
return u.presence(value);
|
3102
|
+
};
|
2867
3103
|
return {
|
2868
3104
|
knife: eval(typeof Knife !== "undefined" && Knife !== null ? Knife.point : void 0),
|
2869
3105
|
url: url,
|
@@ -2879,7 +3115,9 @@ IE 8
|
|
2879
3115
|
puts: puts,
|
2880
3116
|
sprintf: sprintf,
|
2881
3117
|
sprintfWithFormattedArgs: sprintfWithFormattedArgs,
|
2882
|
-
sessionStorage: sessionStorage
|
3118
|
+
sessionStorage: sessionStorage,
|
3119
|
+
popCookie: popCookie,
|
3120
|
+
hash: hash
|
2883
3121
|
};
|
2884
3122
|
})(jQuery);
|
2885
3123
|
|
@@ -2898,8 +3136,10 @@ Most Unpoly interactions emit DOM events that are prefixed with `up:`.
|
|
2898
3136
|
Events often have both present ([`up:modal:open`](/up:modal:open))
|
2899
3137
|
and past forms ([`up:modal:opened`](/up:modal:opened)).
|
2900
3138
|
|
2901
|
-
|
2902
|
-
|
3139
|
+
|
3140
|
+
\#\#\# Preventing events
|
3141
|
+
|
3142
|
+
You can prevent most present form events by calling `preventDefault()`:
|
2903
3143
|
|
2904
3144
|
$(document).on('up:modal:open', function(event) {
|
2905
3145
|
if (event.url == '/evil') {
|
@@ -2909,8 +3149,7 @@ and call `preventDefault()` on the `event` object:
|
|
2909
3149
|
});
|
2910
3150
|
|
2911
3151
|
|
2912
|
-
A better way to bind event listeners
|
2913
|
-
------------------------------------
|
3152
|
+
\#\#\# A better way to bind event listeners
|
2914
3153
|
|
2915
3154
|
Instead of using jQuery to bind an event handler to `document`, you can also
|
2916
3155
|
use the more convenient [`up.on()`](/up.on):
|
@@ -3365,8 +3604,6 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
|
|
3365
3604
|
Unpoly will not boot if the current browser is [not supported](/up.browser.isSupported).
|
3366
3605
|
This leaves you with a classic server-side application on legacy browsers.
|
3367
3606
|
|
3368
|
-
Emits the [`up:framework:boot`](/up:framework:boot) event.
|
3369
|
-
|
3370
3607
|
@function up.boot
|
3371
3608
|
@internal
|
3372
3609
|
*/
|
@@ -4129,8 +4366,8 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
|
|
4129
4366
|
*/
|
4130
4367
|
|
4131
4368
|
/**
|
4132
|
-
If an element
|
4133
|
-
|
4369
|
+
If an element with an `up-data` attribute enters the DOM,
|
4370
|
+
Unpoly will parse the JSON and pass the resulting object to any matching
|
4134
4371
|
[`up.compiler()`](/up.compiler) handlers.
|
4135
4372
|
|
4136
4373
|
For instance, a container for a [Google Map](https://developers.google.com/maps/documentation/javascript/tutorial)
|
@@ -4232,13 +4469,12 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
|
|
4232
4469
|
Browser history
|
4233
4470
|
===============
|
4234
4471
|
|
4235
|
-
|
4236
|
-
|
4237
|
-
We need to work on this page:
|
4472
|
+
In an Unpoly app, every page has an URL.
|
4238
4473
|
|
4239
|
-
|
4240
|
-
|
4241
|
-
|
4474
|
+
[Fragment updates](/up.link) automatically update the URL.
|
4475
|
+
|
4476
|
+
|
4477
|
+
Going back behavior .... configure.
|
4242
4478
|
|
4243
4479
|
@class up.history
|
4244
4480
|
*/
|
@@ -4249,6 +4485,8 @@ We need to work on this page:
|
|
4249
4485
|
u = up.util;
|
4250
4486
|
|
4251
4487
|
/**
|
4488
|
+
Configures behavior when the user goes back or forward in browser history.
|
4489
|
+
|
4252
4490
|
@property up.history.config
|
4253
4491
|
@param {Array} [config.popTargets=['body']]
|
4254
4492
|
An array of CSS selectors to replace when the user goes
|
@@ -4298,6 +4536,13 @@ We need to work on this page:
|
|
4298
4536
|
isCurrentUrl = function(url) {
|
4299
4537
|
return normalizeUrl(url) === currentUrl();
|
4300
4538
|
};
|
4539
|
+
|
4540
|
+
/**
|
4541
|
+
Remembers the given URL so we can offer `up.history.previousUrl()`.
|
4542
|
+
|
4543
|
+
@function observeNewUrl
|
4544
|
+
@internal
|
4545
|
+
*/
|
4301
4546
|
observeNewUrl = function(url) {
|
4302
4547
|
if (nextPreviousUrl) {
|
4303
4548
|
previousUrl = nextPreviousUrl;
|
@@ -4401,9 +4646,9 @@ We need to work on this page:
|
|
4401
4646
|
if (state != null ? state.fromUp : void 0) {
|
4402
4647
|
url = currentUrl();
|
4403
4648
|
return up.log.group("Restoring URL %s", url, function() {
|
4404
|
-
var popSelector;
|
4649
|
+
var popSelector, replaced;
|
4405
4650
|
popSelector = config.popTargets.join(', ');
|
4406
|
-
|
4651
|
+
replaced = up.replace(popSelector, url, {
|
4407
4652
|
history: false,
|
4408
4653
|
title: true,
|
4409
4654
|
reveal: false,
|
@@ -4411,24 +4656,26 @@ We need to work on this page:
|
|
4411
4656
|
saveScroll: false,
|
4412
4657
|
restoreScroll: config.restoreScroll
|
4413
4658
|
});
|
4659
|
+
return replaced.then(function() {
|
4660
|
+
url = currentUrl();
|
4661
|
+
return up.emit('up:history:restored', {
|
4662
|
+
url: url,
|
4663
|
+
message: "Restored location " + url
|
4664
|
+
});
|
4665
|
+
});
|
4414
4666
|
});
|
4415
4667
|
} else {
|
4416
4668
|
return up.puts('Ignoring a state not pushed by Unpoly (%o)', state);
|
4417
4669
|
}
|
4418
4670
|
};
|
4419
4671
|
pop = function(event) {
|
4420
|
-
var state
|
4672
|
+
var state;
|
4421
4673
|
observeNewUrl(currentUrl());
|
4422
4674
|
up.layout.saveScroll({
|
4423
4675
|
url: previousUrl
|
4424
4676
|
});
|
4425
4677
|
state = event.originalEvent.state;
|
4426
|
-
restoreStateOnPop(state);
|
4427
|
-
url = currentUrl();
|
4428
|
-
return up.emit('up:history:restored', {
|
4429
|
-
url: url,
|
4430
|
-
message: "Restored location " + url
|
4431
|
-
});
|
4678
|
+
return restoreStateOnPop(state);
|
4432
4679
|
};
|
4433
4680
|
|
4434
4681
|
/**
|
@@ -4461,7 +4708,7 @@ We need to work on this page:
|
|
4461
4708
|
Note that this will *not* call `location.back()`, but will set
|
4462
4709
|
the link's `up-href` attribute to the actual, previous URL.
|
4463
4710
|
|
4464
|
-
\#\#\#
|
4711
|
+
\#\#\# Example
|
4465
4712
|
|
4466
4713
|
This link ...
|
4467
4714
|
|
@@ -4528,7 +4775,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
4528
4775
|
var slice = [].slice;
|
4529
4776
|
|
4530
4777
|
up.layout = (function($) {
|
4531
|
-
var SCROLL_PROMISE_KEY, anchoredRight, config, finishScrolling, fixedChildren, lastScrollTops, measureObstruction, reset, restoreScroll, reveal, revealOrRestoreScroll, saveScroll, scroll, scrollTops, u, viewportOf, viewportSelector, viewports, viewportsWithin;
|
4778
|
+
var SCROLL_PROMISE_KEY, anchoredRight, config, finishScrolling, firstHashTarget, fixedChildren, lastScrollTops, measureObstruction, reset, restoreScroll, reveal, revealHash, revealOrRestoreScroll, saveScroll, scroll, scrollTops, u, viewportOf, viewportSelector, viewports, viewportsWithin;
|
4532
4779
|
u = up.util;
|
4533
4780
|
|
4534
4781
|
/**
|
@@ -4808,6 +5055,31 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
4808
5055
|
return u.resolvedDeferred();
|
4809
5056
|
}
|
4810
5057
|
};
|
5058
|
+
|
5059
|
+
/**
|
5060
|
+
[Reveals](/up.reveal) an element matching the `#hash` in the current URL.
|
5061
|
+
|
5062
|
+
Other than the default behavior found in browsers, `up.revealHash` works with
|
5063
|
+
[multiple viewports](/up-viewport) and honors [fixed elements](/up-fixed-top) obstructing the user's
|
5064
|
+
view of the viewport.
|
5065
|
+
|
5066
|
+
This is called automatically when the page loads initially.
|
5067
|
+
|
5068
|
+
@function up.layout.revealHash
|
5069
|
+
@experimental
|
5070
|
+
*/
|
5071
|
+
revealHash = function() {
|
5072
|
+
var $match, hash;
|
5073
|
+
if (hash = up.browser.hash()) {
|
5074
|
+
if ($match = firstHashTarget(hash)) {
|
5075
|
+
return reveal($match);
|
5076
|
+
} else {
|
5077
|
+
return u.rejectedPromise();
|
5078
|
+
}
|
5079
|
+
} else {
|
5080
|
+
return u.resolvedPromise();
|
5081
|
+
}
|
5082
|
+
};
|
4811
5083
|
viewportSelector = function() {
|
4812
5084
|
return u.multiSelector(config.viewports);
|
4813
5085
|
};
|
@@ -4986,7 +5258,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
4986
5258
|
@internal
|
4987
5259
|
*/
|
4988
5260
|
revealOrRestoreScroll = function(selectorOrElement, options) {
|
4989
|
-
var $element, $target,
|
5261
|
+
var $element, $target, parsed, revealOptions;
|
4990
5262
|
$element = $(selectorOrElement);
|
4991
5263
|
if (options.restoreScroll) {
|
4992
5264
|
return restoreScroll({
|
@@ -4996,13 +5268,9 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
4996
5268
|
revealOptions = {};
|
4997
5269
|
if (options.source) {
|
4998
5270
|
parsed = u.parseUrl(options.source);
|
4999
|
-
if (
|
5000
|
-
|
5001
|
-
|
5002
|
-
if ($target.length) {
|
5003
|
-
$element = $target;
|
5004
|
-
revealOptions.top = true;
|
5005
|
-
}
|
5271
|
+
if ($target = firstHashTarget(parsed.hash)) {
|
5272
|
+
$element = $target;
|
5273
|
+
revealOptions.top = true;
|
5006
5274
|
}
|
5007
5275
|
}
|
5008
5276
|
return reveal($element, revealOptions);
|
@@ -5074,7 +5342,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
5074
5342
|
Unpoly will then scroll the viewport far enough that the revealed element is fully visible.
|
5075
5343
|
|
5076
5344
|
Instead of using this attribute,
|
5077
|
-
you can also configure a selector in [`up.layout.config.fixedTop`](/up.layout.config#fixedTop).
|
5345
|
+
you can also configure a selector in [`up.layout.config.fixedTop`](/up.layout.config#config.fixedTop).
|
5078
5346
|
|
5079
5347
|
\#\#\# Example
|
5080
5348
|
|
@@ -5094,7 +5362,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
5094
5362
|
Unpoly will then scroll the viewport far enough that the revealed element is fully visible.
|
5095
5363
|
|
5096
5364
|
Instead of using this attribute,
|
5097
|
-
you can also configure a selector in [`up.layout.config.fixedBottom`](/up.layout.config#fixedBottom).
|
5365
|
+
you can also configure a selector in [`up.layout.config.fixedBottom`](/up.layout.config#config.fixedBottom).
|
5098
5366
|
|
5099
5367
|
\#\#\# Example
|
5100
5368
|
|
@@ -5117,7 +5385,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
5117
5385
|
with a CSS of `right: 0` with `position: fixed` or `position:absolute`.
|
5118
5386
|
|
5119
5387
|
Instead of giving this attribute to any affected element,
|
5120
|
-
you can also configure a selector in [`up.layout.config.anchoredRight`](/up.layout.config#anchoredRight).
|
5388
|
+
you can also configure a selector in [`up.layout.config.anchoredRight`](/up.layout.config#config.anchoredRight).
|
5121
5389
|
|
5122
5390
|
\#\#\# Example
|
5123
5391
|
|
@@ -5138,10 +5406,23 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
5138
5406
|
@selector [up-anchored=right]
|
5139
5407
|
@stable
|
5140
5408
|
*/
|
5409
|
+
|
5410
|
+
/**
|
5411
|
+
@function up.layout.firstHashTarget
|
5412
|
+
@internal
|
5413
|
+
*/
|
5414
|
+
firstHashTarget = function(hash) {
|
5415
|
+
if (hash = up.browser.hash(hash)) {
|
5416
|
+
return up.first("[id='" + hash + "'], a[name='" + hash + "']");
|
5417
|
+
}
|
5418
|
+
};
|
5419
|
+
up.on('up:app:booted', revealHash);
|
5141
5420
|
up.on('up:framework:reset', reset);
|
5142
5421
|
return {
|
5143
5422
|
knife: eval(typeof Knife !== "undefined" && Knife !== null ? Knife.point : void 0),
|
5144
5423
|
reveal: reveal,
|
5424
|
+
revealHash: revealHash,
|
5425
|
+
firstHashTarget: firstHashTarget,
|
5145
5426
|
scroll: scroll,
|
5146
5427
|
finishScrolling: finishScrolling,
|
5147
5428
|
config: config,
|
@@ -5161,6 +5442,8 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
|
|
5161
5442
|
|
5162
5443
|
up.reveal = up.layout.reveal;
|
5163
5444
|
|
5445
|
+
up.revealHash = up.layout.revealHash;
|
5446
|
+
|
5164
5447
|
}).call(this);
|
5165
5448
|
|
5166
5449
|
/**
|
@@ -5193,7 +5476,13 @@ is built from these functions. You can use them to extend Unpoly from your
|
|
5193
5476
|
the linked JavaScript file.
|
5194
5477
|
@param {String} [options.fallbacks=['body']]
|
5195
5478
|
When a fragment updates cannot find the requested element, Unpoly will try this list of alternative selectors.
|
5479
|
+
|
5196
5480
|
The first selector that matches an element in the current page (or response) will be used.
|
5481
|
+
If the response contains none of the selectors, an error message will be shown.
|
5482
|
+
|
5483
|
+
It is recommend to always keep `'body'` as the last selector in the last in the case
|
5484
|
+
your server or load balancer renders an error message that does not contain your
|
5485
|
+
application layout.
|
5197
5486
|
@param {String} [options.fallbackTransition='none']
|
5198
5487
|
The transition to use when using a fallback target.
|
5199
5488
|
@stable
|
@@ -5456,14 +5745,14 @@ is built from these functions. You can use them to extend Unpoly from your
|
|
5456
5745
|
*/
|
5457
5746
|
processResponse = function(isSuccess, selector, url, request, xhr, options) {
|
5458
5747
|
var isReloadable, newRequest, query, titleFromXhr, urlFromServer;
|
5459
|
-
options.method = u.normalizeMethod(u.option(
|
5748
|
+
options.method = u.normalizeMethod(u.option(up.protocol.methodFromXhr(xhr), options.method));
|
5460
5749
|
isReloadable = options.method === 'GET';
|
5461
|
-
if (urlFromServer =
|
5750
|
+
if (urlFromServer = up.protocol.locationFromXhr(xhr)) {
|
5462
5751
|
url = urlFromServer;
|
5463
5752
|
if (isSuccess && up.proxy.isCachable(request)) {
|
5464
5753
|
newRequest = {
|
5465
5754
|
url: url,
|
5466
|
-
method:
|
5755
|
+
method: up.protocol.methodFromXhr(xhr),
|
5467
5756
|
target: selector
|
5468
5757
|
};
|
5469
5758
|
up.proxy.alias(request, newRequest);
|
@@ -5504,7 +5793,7 @@ is built from these functions. You can use them to extend Unpoly from your
|
|
5504
5793
|
options.history = false;
|
5505
5794
|
}
|
5506
5795
|
}
|
5507
|
-
if (shouldExtractTitle(options) && (titleFromXhr =
|
5796
|
+
if (shouldExtractTitle(options) && (titleFromXhr = up.protocol.titleFromXhr(xhr))) {
|
5508
5797
|
options.title = titleFromXhr;
|
5509
5798
|
}
|
5510
5799
|
if (options.preload) {
|
@@ -5952,7 +6241,7 @@ is built from these functions. You can use them to extend Unpoly from your
|
|
5952
6241
|
up.first('.field:has(&)', $input); // returns the .field containing $input
|
5953
6242
|
@return {jQuery|Undefined}
|
5954
6243
|
The first element that is neither a ghost or being destroyed,
|
5955
|
-
or `undefined` if no such element was
|
6244
|
+
or `undefined` if no such element was found.
|
5956
6245
|
@experimental
|
5957
6246
|
*/
|
5958
6247
|
first = function(selectorOrElement, options) {
|
@@ -7194,8 +7483,6 @@ Other Unpoly modules contain even more tricks to outsmart network latency:
|
|
7194
7483
|
An array of uppercase HTTP method names. AJAX requests with one of these methods
|
7195
7484
|
will be converted into a `POST` request and carry their original method as a `_method`
|
7196
7485
|
parameter. This is to [prevent unexpected redirect behavior](https://makandracards.com/makandra/38347).
|
7197
|
-
@param {String} [config.wrapMethodParam]
|
7198
|
-
The name of the POST parameter when wrapping HTTP methods in a `POST` request.
|
7199
7486
|
@param {Array<String>} [config.safeMethods]
|
7200
7487
|
An array of uppercase HTTP method names that are considered idempotent.
|
7201
7488
|
The proxy cache will only cache idempotent requests and will clear the entire
|
@@ -7209,7 +7496,6 @@ Other Unpoly modules contain even more tricks to outsmart network latency:
|
|
7209
7496
|
cacheExpiry: 1000 * 60 * 5,
|
7210
7497
|
maxRequests: 4,
|
7211
7498
|
wrapMethods: ['PATCH', 'PUT', 'DELETE'],
|
7212
|
-
wrapMethodParam: '_method',
|
7213
7499
|
safeMethods: ['GET', 'OPTIONS', 'HEAD']
|
7214
7500
|
});
|
7215
7501
|
cacheKey = function(request) {
|
@@ -7335,7 +7621,7 @@ Other Unpoly modules contain even more tricks to outsmart network latency:
|
|
7335
7621
|
@param {String} [request.timeout]
|
7336
7622
|
A timeout in milliseconds for the request.
|
7337
7623
|
|
7338
|
-
If [`up.proxy.config.maxRequests`](/up.proxy.config#maxRequests) is set, the timeout
|
7624
|
+
If [`up.proxy.config.maxRequests`](/up.proxy.config#config.maxRequests) is set, the timeout
|
7339
7625
|
will not include the time spent waiting in the queue.
|
7340
7626
|
@return
|
7341
7627
|
A promise for the response that is API-compatible with the
|
@@ -7525,9 +7811,9 @@ Other Unpoly modules contain even more tricks to outsmart network latency:
|
|
7525
7811
|
}));
|
7526
7812
|
request = u.copy(request);
|
7527
7813
|
request.headers || (request.headers = {});
|
7528
|
-
request.headers[
|
7814
|
+
request.headers[up.protocol.config.targetHeader] = request.target;
|
7529
7815
|
if (u.contains(config.wrapMethods, request.method)) {
|
7530
|
-
request.data = u.appendRequestData(request.data, config.
|
7816
|
+
request.data = u.appendRequestData(request.data, up.protocol.config.methodParam, request.method);
|
7531
7817
|
request.method = 'POST';
|
7532
7818
|
}
|
7533
7819
|
if (u.isFormData(request.data)) {
|
@@ -8467,7 +8753,7 @@ open dialogs with sub-forms, etc. all without losing form state.
|
|
8467
8753
|
options.headers || (options.headers = {});
|
8468
8754
|
options.transition = false;
|
8469
8755
|
options.failTransition = false;
|
8470
|
-
options.headers[
|
8756
|
+
options.headers[up.protocol.config.validateHeader] = options.validate;
|
8471
8757
|
if (!canAjaxSubmit) {
|
8472
8758
|
return u.unresolvablePromise();
|
8473
8759
|
}
|
@@ -8857,12 +9143,11 @@ open dialogs with sub-forms, etc. all without losing form state.
|
|
8857
9143
|
|
8858
9144
|
\#\#\# Redirects
|
8859
9145
|
|
8860
|
-
Unpoly requires
|
9146
|
+
Unpoly requires an additional response headers to detect redirects,
|
8861
9147
|
which are otherwise undetectable for an AJAX client.
|
8862
9148
|
|
8863
|
-
|
8864
|
-
the new request's URL as a response header `X-Up-Location
|
8865
|
-
and the request's HTTP method as `X-Up-Method: GET`.
|
9149
|
+
After the form's action performs a redirect, the next response should echo
|
9150
|
+
the new request's URL as a response header `X-Up-Location`.
|
8866
9151
|
|
8867
9152
|
If you are using Unpoly via the `unpoly-rails` gem, these headers
|
8868
9153
|
are set automatically for every request.
|
@@ -9024,7 +9309,7 @@ open dialogs with sub-forms, etc. all without losing form state.
|
|
9024
9309
|
With the Bootstrap bindings, Unpoly will also look
|
9025
9310
|
for a container with the `form-group` class.
|
9026
9311
|
|
9027
|
-
You can change this default behavior by setting [`up.form.config.validateTargets`](/up.form.config#validateTargets):
|
9312
|
+
You can change this default behavior by setting [`up.form.config.validateTargets`](/up.form.config#config.validateTargets):
|
9028
9313
|
|
9029
9314
|
// Always update the entire form containing the current field ("&")
|
9030
9315
|
up.form.config.validateTargets = ['form &']
|