unpoly-rails 0.52.0 → 0.53.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 24e1c3554a4c11b5fea24fea4397140f394ff0a9
4
- data.tar.gz: 7ade92982a0beb9ddb8cac452aa13ba4dfbada61
3
+ metadata.gz: 6df6e7fea86df29cccc4752d549cd7083be2341f
4
+ data.tar.gz: a7375db94c1351ed6d5f46ef9ee856898fe1b5b7
5
5
  SHA512:
6
- metadata.gz: 2b470bc42358455541f1ec11e3d08b1655be173a911aeb9acd0babe9a8cd47c76fab5128c899b79c8ba4f47baa5a4e6d464a35f0402d6577f866f92699d4f5cf
7
- data.tar.gz: fb755591fd57695660aacde41c4b09f8c3de8fc24bfaa07b24e9d3ab82920c5e76ed96a0cfd8b1a35e46c0740970d776c9f91f3820a4cb230bb8dda20c07d053
6
+ metadata.gz: 5ee1ee46c9d12ad6c40252fa31b8d877f5f32f85d3df461da82c02f7479d81f2a58d104bd3998aa478ace1215762d9be1c7e8d12e341be26aaeeb69ca399a239
7
+ data.tar.gz: 4e835e9180d7b051bb9ec126b760fc7766711ae2bca4993cc0f9fe04785e8c53a039c3ae4aed850a44bf2165b1d4adbe64b19c2ee383b8c897fccd8607114602
data/CHANGELOG.md CHANGED
@@ -6,6 +6,56 @@ 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
+
10
+ Unreleased
11
+ ----------
12
+
13
+ ### New module: Passive updates
14
+
15
+ Thi work-in-progress package [`up.radio`](/up.radio) will contain functionality to
16
+ passively receive updates from the server. Currently the following functionality is implemented:
17
+
18
+ - Elements with an [`[up-hungry]`](/up-hungry) attribute are [updated](/up.replace) whenever there is a matching element found in a successful response. The element is replaced even when it isn't [targeted](/a-up-target) directly.
19
+
20
+ Use cases for this are unread message counters or notification flashes. Such elements often live in the layout, outside of the content area that is being replaced.
21
+ - When a reserver response contains a `<meta name="csrf-param">` or `<meta name="csrf-token">` element, it is automatically updated in the current page.
22
+
23
+
24
+ ### General
25
+
26
+ - Changes when generating CSS selectors for elements:
27
+ - `[aria-label]` attributes are used if no better attributes exist (like `[id]` or `[up-id]` attributes).
28
+ - Attribute values with quotes are now escaped if they appear in an attribute selector.
29
+ - Attribute selectors now use double quotes instead of single quotes.
30
+ - When a `[name]` attribute is used, the tag name is also used. E.g. `meta[name="csrf-token"]`.
31
+ - Element IDs that contain non-word characters (e.g. slashes, spaces, dots), will now generate an attribute selector like `[id="foo/bar"]`.
32
+
33
+ ### Forms
34
+
35
+ - You can give forms an `[up-fail-reveal]` attribute to indicate which element should be [revealed](/up.reveal) when the server responds with an error. You may use this, for example, to reveal the first validation error message:
36
+ ```
37
+ <form up-target=".content" up-fail-reveal=".error">
38
+ ...
39
+ </form>
40
+ ```
41
+ - Forms with an `[up-reveal]` attribute will now only honor the attribute when the form submission was successful.
42
+ - Forms with an `[up-restore-scroll]` attribute will now only honor the attribute when the form submission was successful.
43
+ - Forms with an `[up-reveal="css-selector"]` attribute will no longer crash when the selector could not be found.
44
+ - Fix a bug where you couldn't submit a form if it's ID contains a slash character ([#46](https://github.com/unpoly/unpoly/issues/46)).
45
+
46
+ ### Links
47
+
48
+ - You can give links an `[up-fail-reveal]` attribute to indicate which element should be [revealed](/up.reveal) when the server responds with an error
49
+ - Links with an `[up-reveal]` attribute will now only honor the attribute when the link could be followed successfully.
50
+ - Links with an `[up-restore-scroll]` attribute will now only honor the attribute when the link could be followed successfully.
51
+ - Links with an `[up-reveal="css-selector"]` attribute will no longer crash when the selector could not be found.
52
+
53
+ ### Animations
54
+
55
+ - When [replacing](/up.replace) multiple elements, it is no longer possible to use different [transitions](/up.morph) for each element. The same transition is always applied to all elements.
56
+
57
+
58
+
9
59
  0.52.0
10
60
  ------
11
61
 
@@ -832,9 +882,9 @@ This is a major update with some breaking changes. Expect a few more updates lik
832
882
  - Loading modals and popups will now open if there is a fragment update between the modal/popup's
833
883
  request and response.
834
884
  - [`up.follow()`](/up.follow) and [`up.replace()`](/up.replace) now have an option `{ failTarget }`.
835
- Use it to define the selector to replace if the server responds with a non-200 status code.
885
+ Use it to define the selector to replace if the server responds with an error.
836
886
  - [`[up-target]`](/a-up-target) and [`up-follow`](/a-up-follow) now have a modifying attribute `up-fail-target`.
837
- Use it to define the selector to replace if the server responds with a non-200 status code.
887
+ Use it to define the selector to replace if the server responds with an error.
838
888
  - New utility method [`up.util.reject()`](/up.util.reject)
839
889
  - New utility method [`up.util.only()`](/up.util.only)
840
890
  - New utility method [`up.util.except()`](/up.util.except)
data/dist/unpoly.js CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  (function() {
7
7
  window.up = {
8
- version: "0.52.0",
8
+ version: "0.53.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 [Lodash](https://lodash.com/).
41
41
  @function up.util.noop
42
42
  @experimental
43
43
  */
44
- var $createElementFromSelector, $createPlaceholder, $submittingButton, DivertibleChain, ESCAPE_HTML_ENTITY_MAP, all, always, any, appendRequestData, assign, assignPolyfill, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElementFromHtml, cssAnimate, detachWith, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, evalOption, except, extractOptions, fail, fixedToAbsolute, flatten, forceCompositing, forceRepaint, horizontalScreenHalf, identity, intersect, isArray, isBlank, isBodyDescendant, isCrossDomain, isDefined, isDetached, isElement, isFixed, isFormData, isFunction, isGiven, isJQuery, isMissing, isNull, isNumber, isObject, isOptions, isPresent, isPromise, isStandardPort, isString, isTruthy, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, last, map, margins, measure, memoize, merge, mergeRequestData, methodAllowsPayload, microtask, multiSelector, newDeferred, nextFrame, nonUpClasses, noop, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, opacity, openConfig, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, promiseTimer, reject, rejectOnError, remove, renameKey, requestDataAsArray, requestDataAsQuery, requestDataFromForm, scrollbarWidth, select, selectInDynasty, selectInSubtree, selectorForElement, sequence, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, toArray, trim, unJQuery, uniq, unresolvablePromise, unwrapElement, whenReady;
44
+ var $createElementFromSelector, $createPlaceholder, $submittingButton, DivertibleChain, ESCAPE_HTML_ENTITY_MAP, all, always, any, appendRequestData, assign, assignPolyfill, attributeSelector, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElementFromHtml, cssAnimate, detachWith, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, evalOption, except, extractOptions, fail, fixedToAbsolute, flatten, forceCompositing, forceRepaint, horizontalScreenHalf, identity, intersect, isArray, isBlank, isBodyDescendant, isCrossDomain, isDefined, isDetached, isElement, isFixed, isFormData, isFunction, isGiven, isJQuery, isMissing, isNull, isNumber, isObject, isOptions, isPresent, isPromise, isStandardPort, isString, isTruthy, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, last, map, margins, measure, memoize, merge, mergeRequestData, methodAllowsPayload, microtask, multiSelector, newDeferred, nextFrame, nonUpClasses, noop, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, opacity, openConfig, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, promiseTimer, reject, rejectOnError, remove, renameKey, requestDataAsArray, requestDataAsQuery, requestDataFromForm, scrollbarWidth, select, selectInDynasty, selectInSubtree, selectorForElement, sequence, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, toArray, trim, unJQuery, uniq, unresolvablePromise, unwrapElement, whenReady;
45
45
  noop = $.noop;
46
46
 
47
47
  /**
@@ -252,26 +252,37 @@ that might save you from loading something like [Lodash](https://lodash.com/).
252
252
  @experimental
253
253
  */
254
254
  selectorForElement = function(element) {
255
- var $element, classes, i, id, klass, len, name, selector, upId;
255
+ var $element, ariaLabel, classes, i, id, klass, len, name, selector, tagName, upId;
256
256
  $element = $(element);
257
257
  selector = void 0;
258
+ tagName = $element.prop('tagName').toLowerCase();
258
259
  if (upId = presence($element.attr("up-id"))) {
259
- selector = "[up-id='" + upId + "']";
260
+ selector = attributeSelector('up-id', upId);
260
261
  } else if (id = presence($element.attr("id"))) {
261
- selector = "#" + id;
262
+ if (id.match(/^[a-z0-9\-_]+$/i)) {
263
+ selector = "#" + id;
264
+ } else {
265
+ selector = attributeSelector('id', id);
266
+ }
262
267
  } else if (name = presence($element.attr("name"))) {
263
- selector = "[name='" + name + "']";
268
+ selector = tagName + attributeSelector('name', name);
264
269
  } else if (classes = presence(nonUpClasses($element))) {
265
270
  selector = '';
266
271
  for (i = 0, len = classes.length; i < len; i++) {
267
272
  klass = classes[i];
268
273
  selector += "." + klass;
269
274
  }
275
+ } else if (ariaLabel = presence($element.attr("aria-label"))) {
276
+ selector = attributeSelector('aria-label', ariaLabel);
270
277
  } else {
271
- selector = $element.prop('tagName').toLowerCase();
278
+ selector = tagName;
272
279
  }
273
280
  return selector;
274
281
  };
282
+ attributeSelector = function(attribute, value) {
283
+ value = value.replace(/"/g, '\\"');
284
+ return "[" + attribute + "=\"" + value + "\"]";
285
+ };
275
286
  nonUpClasses = function($element) {
276
287
  var classString, classes;
277
288
  classString = $element.attr('class') || '';
@@ -2436,6 +2447,7 @@ that might save you from loading something like [Lodash](https://lodash.com/).
2436
2447
  function ExtractCascade(selector, options) {
2437
2448
  this.oldPlanNotFound = bind(this.oldPlanNotFound, this);
2438
2449
  this.matchingPlanNotFound = bind(this.matchingPlanNotFound, this);
2450
+ this.hungrySteps = bind(this.hungrySteps, this);
2439
2451
  this.bestMatchingSteps = bind(this.bestMatchingSteps, this);
2440
2452
  this.bestPreflightSelector = bind(this.bestPreflightSelector, this);
2441
2453
  this.detectPlan = bind(this.detectPlan, this);
@@ -2446,13 +2458,15 @@ that might save you from loading something like [Lodash](https://lodash.com/).
2446
2458
  humanizedTarget: 'selector',
2447
2459
  layer: 'auto'
2448
2460
  });
2461
+ this.options.transition = u.option(this.options.transition, this.options.animation);
2462
+ this.options.hungry = u.option(this.options.hungry, true);
2449
2463
  this.candidates = this.buildCandidates(selector);
2450
2464
  this.plans = u.map(this.candidates, (function(_this) {
2451
2465
  return function(candidate, i) {
2452
2466
  var planOptions;
2453
2467
  planOptions = u.copy(_this.options);
2454
2468
  if (i > 0) {
2455
- planOptions.transition = up.dom.config.fallbackTransition;
2469
+ planOptions.transition = u.option(up.dom.config.fallbackTransition, _this.options.transition);
2456
2470
  }
2457
2471
  return new up.ExtractPlan(candidate, planOptions);
2458
2472
  };
@@ -2503,12 +2517,34 @@ that might save you from loading something like [Lodash](https://lodash.com/).
2503
2517
  ExtractCascade.prototype.bestMatchingSteps = function() {
2504
2518
  var plan;
2505
2519
  if (plan = this.matchingPlan()) {
2506
- return plan.steps;
2520
+ return plan.steps.concat(this.hungrySteps());
2507
2521
  } else {
2508
2522
  return this.matchingPlanNotFound();
2509
2523
  }
2510
2524
  };
2511
2525
 
2526
+ ExtractCascade.prototype.hungrySteps = function() {
2527
+ var $hungries, $hungry, $newHungry, hungry, j, len, selector, steps, transition;
2528
+ steps = [];
2529
+ if (this.options.hungry) {
2530
+ $hungries = up.radio.hungrySelector().select();
2531
+ for (j = 0, len = $hungries.length; j < len; j++) {
2532
+ hungry = $hungries[j];
2533
+ $hungry = $(hungry);
2534
+ selector = u.selectorForElement($hungry);
2535
+ if ($newHungry = this.options.response.first(selector)) {
2536
+ transition = u.option(up.radio.config.hungryTransition, this.options.transition);
2537
+ steps.push({
2538
+ $old: $hungry,
2539
+ $new: $newHungry,
2540
+ transition: transition
2541
+ });
2542
+ }
2543
+ }
2544
+ }
2545
+ return steps;
2546
+ };
2547
+
2512
2548
  ExtractCascade.prototype.matchingPlanNotFound = function() {
2513
2549
  var inspectAction, message;
2514
2550
  if (this.newPlan()) {
@@ -2561,7 +2597,7 @@ that might save you from loading something like [Lodash](https://lodash.com/).
2561
2597
  this.findOld = bind(this.findOld, this);
2562
2598
  this.origin = options.origin;
2563
2599
  this.selector = up.dom.resolveSelector(selector, options.origin);
2564
- this.transition = options.transition || options.animation || 'none';
2600
+ this.transition = options.transition;
2565
2601
  this.response = options.response;
2566
2602
  this.oldLayer = options.layer;
2567
2603
  this.steps = this.parseSteps();
@@ -2616,30 +2652,26 @@ that might save you from loading something like [Lodash](https://lodash.com/).
2616
2652
  */
2617
2653
 
2618
2654
  ExtractPlan.prototype.parseSteps = function() {
2619
- var comma, disjunction, transitions;
2620
- if (u.isString(this.transition)) {
2621
- transitions = this.transition.split(comma);
2622
- } else {
2623
- transitions = [this.transition];
2624
- }
2655
+ var comma, disjunction;
2625
2656
  comma = /\ *,\ */;
2626
2657
  disjunction = this.selector.split(comma);
2627
- return u.map(disjunction, function(literal, i) {
2628
- var literalParts, pseudoClass, selector, transition;
2629
- literalParts = literal.match(/^(.+?)(?:\:(before|after))?$/);
2630
- literalParts || up.fail('Could not parse selector literal "%s"', literal);
2631
- selector = literalParts[1];
2632
- if (selector === 'html') {
2633
- selector = 'body';
2634
- }
2635
- pseudoClass = literalParts[2];
2636
- transition = transitions[i] || u.last(transitions);
2637
- return {
2638
- selector: selector,
2639
- pseudoClass: pseudoClass,
2640
- transition: transition
2658
+ return u.map(disjunction, (function(_this) {
2659
+ return function(literal, i) {
2660
+ var literalParts, pseudoClass, selector;
2661
+ literalParts = literal.match(/^(.+?)(?:\:(before|after))?$/);
2662
+ literalParts || up.fail('Could not parse selector literal "%s"', literal);
2663
+ selector = literalParts[1];
2664
+ if (selector === 'html') {
2665
+ selector = 'body';
2666
+ }
2667
+ pseudoClass = literalParts[2];
2668
+ return {
2669
+ selector: selector,
2670
+ pseudoClass: pseudoClass,
2671
+ transition: _this.transition
2672
+ };
2641
2673
  };
2642
- });
2674
+ })(this));
2643
2675
  };
2644
2676
 
2645
2677
  return ExtractPlan;
@@ -3495,17 +3527,23 @@ That said, there is an **optional** protocol your server can use to
3495
3527
  exchange additional information when Unpoly is [updating fragments](/up.link).
3496
3528
 
3497
3529
  While the protocol can help you optimize performance and handle some
3498
- edge cases, implementing it is entirely optional. For instance,
3530
+ edge cases, implementing it is **entirely optional**. For instance,
3499
3531
  `unpoly.com` itself is a static site that uses Unpoly on the frontend
3500
3532
  and doesn't even have a server component.
3501
3533
 
3502
- If you have [installed Unpoly as a Rails gem](/install/rails), the protocol
3503
- is already implemented and you will get some
3504
- [Ruby bindings](https://github.com/unpoly/unpoly/blob/master/README_RAILS.md)
3505
- in your controllers and views. If your server-side app uses another language
3506
- or framework, you should be able to implement the protocol in a very short time.
3534
+ ## Existing implementations
3535
+
3536
+ You should be able to implement the protocol in a very short time.
3537
+ There are existing implementations for various web frameworks:
3538
+
3539
+ - [Ruby on Rails](/install/rails)
3540
+ - [Roda](https://github.com/adam12/roda-unpoly)
3541
+ - [Rack](https://github.com/adam12/rack-unpoly) (Sinatra, Padrino, Hanami, Cuba, ...)
3542
+ - [Phoenix](https://elixirforum.com/t/unpoly-a-framework-like-turbolinks/3614/15) (Elixir)
3507
3543
 
3508
3544
 
3545
+ ## Protocol details
3546
+
3509
3547
  \#\#\# Redirect detection for IE11
3510
3548
 
3511
3549
  On Internet Explorer 11, Unpoly cannot detect the final URL after a redirect.
@@ -6112,7 +6150,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
6112
6150
  */
6113
6151
  reveal = function(elementOrSelector, options) {
6114
6152
  var $element;
6115
- $element = $(elementOrSelector);
6153
+ $element = $(elementOrSelector).first();
6116
6154
  up.puts('Revealing fragment %o', $element.get(0));
6117
6155
  options = u.options(options);
6118
6156
  return u.rejectOnError(function() {
@@ -6390,7 +6428,9 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
6390
6428
  $element = up.first(selector) || $element;
6391
6429
  revealOptions.top = true;
6392
6430
  }
6393
- return reveal($element, revealOptions);
6431
+ if ($element.length) {
6432
+ return reveal($element, revealOptions);
6433
+ }
6394
6434
  }
6395
6435
  return Promise.resolve();
6396
6436
  };
@@ -6604,13 +6644,15 @@ is built from these functions. You can use them to extend Unpoly from your
6604
6644
  It is recommend to always keep `'body'` as the last selector in the last in the case
6605
6645
  your server or load balancer renders an error message that does not contain your
6606
6646
  application layout.
6607
- @param {string} [options.fallbackTransition='none']
6608
- The transition to use when using a fallback target.
6647
+ @param {string} [options.fallbackTransition=null]
6648
+ The transition to use when using a [fallback target](/#options.fallbacks).
6649
+
6650
+ By default this is not set and the original replacement's transition is used.
6609
6651
  @stable
6610
6652
  */
6611
6653
  config = u.config({
6612
6654
  fallbacks: ['body'],
6613
- fallbackTransition: 'none'
6655
+ fallbackTransition: null
6614
6656
  });
6615
6657
  reset = function() {
6616
6658
  return config.reset();
@@ -6774,8 +6816,11 @@ is built from these functions. You can use them to extend Unpoly from your
6774
6816
  If set to `false`, the history will remain unchanged.
6775
6817
  @param {boolean|string} [options.source=true]
6776
6818
  @param {boolean|string} [options.reveal=false]
6777
- Whether to [reveal](/up.reveal) the element being updated, by
6778
- scrolling its containing viewport.
6819
+ Whether to [reveal](/up.reveal) the new fragment.
6820
+
6821
+ You can also pass a CSS selector for the element to reveal.
6822
+ @param {boolean|string} [options.failReveal=false]
6823
+ Whether to [reveal](/up.reveal) the new fragment when the server responds with an error.
6779
6824
 
6780
6825
  You can also pass a CSS selector for the element to reveal.
6781
6826
  @param {boolean} [options.restoreScroll=false]
@@ -6828,10 +6873,13 @@ is built from these functions. You can use them to extend Unpoly from your
6828
6873
  });
6829
6874
  failureOptions = u.merge(options, {
6830
6875
  humanizedTarget: 'failure target',
6831
- provideTarget: void 0
6876
+ provideTarget: void 0,
6877
+ restoreScroll: false,
6878
+ hungry: false
6832
6879
  });
6833
6880
  u.renameKey(failureOptions, 'failTransition', 'transition');
6834
6881
  u.renameKey(failureOptions, 'failLayer', 'layer');
6882
+ u.renameKey(failureOptions, 'failReveal', 'reveal');
6835
6883
  try {
6836
6884
  improvedTarget = bestPreflightSelector(selectorOrElement, successOptions);
6837
6885
  improvedFailTarget = bestPreflightSelector(options.failTarget, failureOptions);
@@ -9181,7 +9229,14 @@ new page is loading.
9181
9229
  The selector to replace.
9182
9230
  Defaults to the `[up-target]`, `[up-modal]` or `[up-popup]` attribute on `link`.
9183
9231
  If no target is given, the `<body>` element will be replaced.
9232
+ @param {boolean|string} [options.reveal=true]
9233
+ Whether to [reveal](/up.reveal) the target fragment after it was replaced.
9234
+
9235
+ You can also pass a CSS selector for the element to reveal.
9236
+ @param {boolean|string} [options.failReveal=true]
9237
+ Whether to [reveal](/up.reveal) the target fragment when the server responds with an error.
9184
9238
 
9239
+ You can also pass a CSS selector for the element to reveal.
9185
9240
  @return {Promise}
9186
9241
  A promise that will be fulfilled when the link destination
9187
9242
  has been loaded and rendered.
@@ -9221,6 +9276,7 @@ new page is loading.
9221
9276
  options.failTransition = u.option(options.failTransition, u.castedAttr($link, 'up-fail-transition'), 'none');
9222
9277
  options.history = u.option(options.history, u.castedAttr($link, 'up-history'));
9223
9278
  options.reveal = u.option(options.reveal, u.castedAttr($link, 'up-reveal'), true);
9279
+ options.failReveal = u.option(options.failReveal, u.castedAttr($link, 'up-fail-reveal'), true);
9224
9280
  options.cache = u.option(options.cache, u.castedAttr($link, 'up-cache'));
9225
9281
  options.restoreScroll = u.option(options.restoreScroll, u.castedAttr($link, 'up-restore-scroll'));
9226
9282
  options.method = followMethod($link, options);
@@ -9424,10 +9480,10 @@ new page is loading.
9424
9480
  @param {string} [up-transition='none']
9425
9481
  The [transition](/up.motion) to use for morphing between the old and new elements.
9426
9482
  @param [up-fail-target='body']
9427
- The selector to replace if the server responds with a non-200 status code.
9483
+ The selector to replace if the server responds with an error.
9428
9484
  @param {string} [up-fail-transition='none']
9429
9485
  The [transition](/up.motion) to use for morphing between the old and new elements
9430
- when the server responds with a non-200 status code.
9486
+ when the server responds with an error.
9431
9487
  @param {string} [up-fallback]
9432
9488
  The selector to update when the original target was not found in the page.
9433
9489
  @param {string} [up-href]
@@ -9437,7 +9493,13 @@ new page is loading.
9437
9493
  A message that will be displayed in a cancelable confirmation dialog
9438
9494
  before the link is followed.
9439
9495
  @param {string} [up-reveal='true']
9440
- Whether to reveal the target element within its viewport before updating.
9496
+ Whether to reveal the target element after it was replaced.
9497
+
9498
+ You can also pass a CSS selector for the element to reveal.
9499
+ @param {string} [up-fail-reveal='true']
9500
+ Whether to reveal the target element when the server responds with an error.
9501
+
9502
+ You can also pass a CSS selector for the element to reveal.
9441
9503
  @param {string} [up-restore-scroll='false']
9442
9504
  Whether to restore previously known scroll position of all viewports
9443
9505
  within the target selector.
@@ -9497,14 +9559,14 @@ new page is loading.
9497
9559
  @param {string} [up-method='get']
9498
9560
  The HTTP method to use for the request.
9499
9561
  @param [up-fail-target='body']
9500
- The selector to replace if the server responds with a non-200 status code.
9562
+ The selector to replace if the server responds with an error.
9501
9563
  @param {string} [up-fallback]
9502
9564
  The selector to update when the original target was not found in the page.
9503
9565
  @param {string} [up-transition='none']
9504
9566
  The [transition](/up.motion) to use for morphing between the old and new elements.
9505
9567
  @param {string} [up-fail-transition='none']
9506
9568
  The [transition](/up.motion) to use for morphing between the old and new elements
9507
- when the server responds with a non-200 status code.
9569
+ when the server responds with an error.
9508
9570
  @param [up-href]
9509
9571
  The destination URL to follow.
9510
9572
  If omitted, the the link's `href` attribute will be used.
@@ -9781,8 +9843,14 @@ open dialogs with sub-forms, etc. all without losing form state.
9781
9843
  The delay before the transition starts. See [`up.morph()`](/up.morph).
9782
9844
  @param {string} [options.easing]
9783
9845
  The timing function that controls the transition's acceleration. [`up.morph()`](/up.morph).
9784
- @param {Element|jQuery|string} [options.reveal=true]
9785
- Whether to reveal the target element within its viewport.
9846
+ @param {Element|string} [options.reveal=true]
9847
+ Whether to reveal the target fragment after it was replaced.
9848
+
9849
+ You can also pass a CSS selector for the element to reveal.
9850
+ @param {boolean|string} [options.failReveal=true]
9851
+ Whether to [reveal](/up.reveal) the target fragment when the server responds with an error.
9852
+
9853
+ You can also pass a CSS selector for the element to reveal.
9786
9854
  @param {boolean} [options.restoreScroll]
9787
9855
  If set to `true`, this will attempt to [`restore scroll positions`](/up.restoreScroll)
9788
9856
  previously seen on the destination URL.
@@ -9814,13 +9882,14 @@ open dialogs with sub-forms, etc. all without losing form state.
9814
9882
  target = u.option(options.target, $form.attr('up-target'), 'body');
9815
9883
  url = u.option(options.url, $form.attr('action'), up.browser.url());
9816
9884
  options.failTarget = u.option(options.failTarget, $form.attr('up-fail-target')) || u.selectorForElement($form);
9885
+ options.reveal = u.option(options.reveal, u.castedAttr($form, 'up-reveal'), true);
9886
+ options.failReveal = u.option(options.failReveal, u.castedAttr($form, 'up-fail-reveal'), true);
9817
9887
  options.fallback = u.option(options.fallback, $form.attr('up-fallback'));
9818
9888
  options.history = u.option(options.history, u.castedAttr($form, 'up-history'), true);
9819
9889
  options.transition = u.option(options.transition, u.castedAttr($form, 'up-transition'), 'none');
9820
9890
  options.failTransition = u.option(options.failTransition, u.castedAttr($form, 'up-fail-transition'), 'none');
9821
9891
  options.method = u.option(options.method, $form.attr('up-method'), $form.attr('data-method'), $form.attr('method'), 'post').toUpperCase();
9822
9892
  options.headers = u.option(options.headers, {});
9823
- options.reveal = u.option(options.reveal, u.castedAttr($form, 'up-reveal'), true);
9824
9893
  options.cache = u.option(options.cache, u.castedAttr($form, 'up-cache'));
9825
9894
  options.restoreScroll = u.option(options.restoreScroll, u.castedAttr($form, 'up-restore-scroll'));
9826
9895
  options.origin = u.option(options.origin, $form);
@@ -10232,7 +10301,7 @@ open dialogs with sub-forms, etc. all without losing form state.
10232
10301
  If omitted, Unpoly will replace the `<form>` tag itself, assuming that the
10233
10302
  server has echoed the form with validation errors.
10234
10303
  @param [up-fallback]
10235
- The selector to replace if the server responds with a non-200 status code.
10304
+ The selector to replace if the server responds with an error.
10236
10305
  @param {string} [up-transition]
10237
10306
  The animation to use when the form is replaced after a successful submission.
10238
10307
  @param {string} [up-fail-transition]
@@ -10261,7 +10330,18 @@ open dialogs with sub-forms, etc. all without losing form state.
10261
10330
  The name of the layer that ought to be updated if the server sends a
10262
10331
  non-200 status code.
10263
10332
  @param {string} [up-reveal='true']
10264
- Whether to reveal the target element within its viewport before updating.
10333
+ Whether to reveal the target element after it was replaced.
10334
+
10335
+ You can also pass a CSS selector for the element to reveal.
10336
+ @param {string} [up-fail-reveal='true']
10337
+ Whether to reveal the target element when the server responds with an error.
10338
+
10339
+ You can also pass a CSS selector for the element to reveal. You may use this, for example,
10340
+ to reveal the first validation error message:
10341
+
10342
+ <form up-target=".content" up-fail-reveal=".error">
10343
+ ...
10344
+ </form>
10265
10345
  @param {string} [up-restore-scroll='false']
10266
10346
  Whether to restore previously known scroll position of all viewports
10267
10347
  within the target selector.
@@ -12747,6 +12827,75 @@ Once the response is received the URL will change to `/bar` and the `up-active`
12747
12827
 
12748
12828
  }).call(this);
12749
12829
 
12830
+ /**
12831
+ Passive updates
12832
+ ===============
12833
+
12834
+ This work-in-progress package will contain functionality to
12835
+ passively receive updates from the server.
12836
+
12837
+ @class up.radio
12838
+ */
12839
+
12840
+ (function() {
12841
+ up.radio = (function($) {
12842
+ var config, hungrySelector, reset, u;
12843
+ u = up.util;
12844
+
12845
+ /**
12846
+ Configures defaults for passive updates.
12847
+
12848
+ @property up.radio.config
12849
+ @param {Array<string>} [options.hungry]
12850
+ An array of CSS selectors that is replaced whenever a matching element is found in a response.
12851
+ These elements are replaced even when they were not targeted directly.
12852
+
12853
+ By default this contains the [`[up-hungry]`](/up-hungry) attribute as well as
12854
+ `<meta name="csrf-param">` and `<meta name="csrf-token">` tags.
12855
+ @param {string} [options.hungryTransition=null]
12856
+ The transition to use when a [hungry element](/up-hungry) is replacing itself
12857
+ while another target is replaced.
12858
+
12859
+ By default this is not set and the original replacement's transition is used.
12860
+ @stable
12861
+ */
12862
+ config = u.config({
12863
+ hungry: ['[up-hungry]', 'meta[name="csrf-param"]', 'meta[name="csrf-token"]'],
12864
+ hungryTransition: null
12865
+ });
12866
+ reset = function() {
12867
+ return config.reset();
12868
+ };
12869
+
12870
+ /**
12871
+ @function up.radio.hungrySelector
12872
+ @internal
12873
+ */
12874
+ hungrySelector = function() {
12875
+ return u.multiSelector(config.hungry);
12876
+ };
12877
+
12878
+ /**
12879
+ Elements with this attribute are [updated](/up.replace) whenever there is a
12880
+ matching element found in a successful response. The element is replaced even
12881
+ when it isn't [targeted](/a-up-target) directly.
12882
+
12883
+ Use cases for this are unread message counters or notification flashes.
12884
+ Such elements often live in the layout, outside of the content area that is
12885
+ being replaced.
12886
+
12887
+ @selector [up-hungry]
12888
+ @stable
12889
+ */
12890
+ up.on('up:framework:reset', reset);
12891
+ return {
12892
+ config: config,
12893
+ hungrySelector: hungrySelector
12894
+ };
12895
+ })(jQuery);
12896
+
12897
+ }).call(this);
12898
+
12750
12899
  /**
12751
12900
  Play nice with Rails UJS
12752
12901
  ========================