unpoly-rails 0.33.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of unpoly-rails might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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 &']
|