unpoly-rails 2.0.0.pre.rc8 → 2.0.1

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
  SHA256:
3
- metadata.gz: 5936610be1c08e8b5957ab3b7610af252b571b2cf9588666fba8459073098001
4
- data.tar.gz: b5e2ee5e13e1b579b30804aa645e0deee1c5505cf0bf461e81acf74e0292fb99
3
+ metadata.gz: ca1b97c24b080cd0a84254cb393b9118772b416f4383f1a4389e9c161ce6e843
4
+ data.tar.gz: cd31715c151bcb4f1966ef479b5752134ac3ae9c7245fe65054e1f78cae69d1f
5
5
  SHA512:
6
- metadata.gz: 4d873356aa058dc299dbbdb0966d2cb8a43a05f17dc242c7c9b39c75cad02077876dfb4ffbd149a2d36185f39b16d7f42179ca441976b6429659caf0deb8a650
7
- data.tar.gz: 17d3746672f98c703230efc9b641aa16b77d71b40911226533797776f4a58c3807b2ebb03cc27951effbd0deab714ccaebe6065b84d58c09c5b8878508f20448
6
+ metadata.gz: f38f09fa8cdfa73f24885e406907766f1a7698361d815a5969d870c70ac02de0b660266f5c36ba4f56121ee4daadde2b54103e233fbe41b255290fea25a04d38
7
+ data.tar.gz: 0c784690fb34f37c51a6fe090b2669c49b6d3f1b6076ec50caacc6fdc3254163b59d6a80cfc62970280e3ea254709822d61ab5c3c9880a7f80d56f3cc5a4bc81
data/CHANGELOG.md CHANGED
@@ -3,67 +3,145 @@ Changelog
3
3
 
4
4
  Changes to this project will be documented in this file.
5
5
 
6
+ If you're upgrading from an older Unpoly version you should load [`unpoly-migrate.js`](https://unpoly.com/changes/upgrading) to enable deprecated APIs.
7
+
6
8
  You may browse a formatted and hyperlinked version of this file at <https://unpoly.com/changes>.
7
9
 
8
10
 
11
+ 2.0.1
12
+ -----
13
+
14
+ This bugfix release addresses some issues user reported when upgrading to Unpoly 2:
15
+
16
+ - Fix a bug where [`unpoly-migrate.js`](https://unpoly.com/changes/upgrading) would crash when loaded.
17
+ - Fix a bug where transitions would crash when some { scroll } options were also used (#187)
18
+ - Users can now now change the spacing between a popup overlay and the opening link by giving `<up-popup>` a CSS margin.
19
+
20
+
9
21
  2.0.0
10
22
  -----
11
23
 
12
- [See Unpoly 2 slides](http://triskweline.de/unpoly2-slides/)
13
-
14
- TODO
15
- ----
16
-
17
- This list is **far** from complete.
18
-
19
- - up.network.config.slowDelay is now 800 (up from 300)
20
- - up.network.config.cacheSize is now 50 (down from 70)
21
- - up.network.isBusy() / isIdle() takes preload events into account
22
- - up.observe() callback may return a promise that will prevent callback calls while running
23
- - `[aria-label]` attributes are no longer used to build a target selector
24
- - Options removed form modals: up-width, up-max-width, up-height. Use up-size or up-class.
25
- - Failed responses now change the URL
26
- - TODO ...
27
- - up.history.config.restoreScroll has been removed.
28
- - Feedback works when a layer has no history
29
- - Layer A11Y
30
- - inert
31
- - aria-hidden
32
- - focus new
33
- - focus return on close
34
- - up.nav sets [aria-current]
35
- - up.history.config.enabled
36
- - Requests sent by Unpoly no longer have a `X-Requested-With: XMLHttpRequest` header.
37
- If you need that old behavior: up.on('up:request:load', function(event) { event.request.headers['X-Requested-With'] = 'XMLHttpRequest' })
38
- - up.network.config.requestMetaKeys
39
- - up:link:follow is no longer sent when preloading, up:link:preload still is
40
- - Preserve focus when validating forms; Add { focus } option for fragment update
41
- - up.Request.prototype.isFatalError() has been removed without replacement. Network errors now reject with an error, and not a response.
42
- - [up-main], [up-main=overlay], [up-main=modal]
43
- - parseSelector can parse attribute selectors with prefix, infix, suffix, space-separated, dash-separated
44
- - up.validate() may now be called with a form element
45
- - validating emits up:form:validate instead of up:form:submit
46
- - When a compiler throws an error, other compilers will now run anyway
47
- - When a destructor throws an error, other destructors will now run anyway
48
- - Bootstrap integration
49
- - Minimal: active, nav, navbar
50
- - Bootstrap modal styles are no longer used for Unpoly modals
51
- - Now supports three major Bootstrap versions:
52
- - unpoly-bootstrap3.js
53
- - unpoly-bootstrap4.js
54
- - unpoly-bootstrap5.js
55
- - Hungry elements no longer get the transition by default. You need to set [up-transition] on the hungry element.
56
- - Rejections are now shown if the log is enabled
57
- - up.on() can passive: true
58
- - Preloads on touchstart and mousedown
59
- - Digit groups separators (`60_000`) are a stage 3 ES6 feature and also supported in number attributes.
24
+ Unpoly 2 ships with many new features and API improvements, unlocking many use cases that were not possible with Unpoly 1.
25
+
26
+ For an in-depth guide to all changes, see our [Unpoly 2 presentation](http://triskweline.de/unpoly2-slides/) (150 slides).
27
+
28
+ If you're upgrading from an older Unpoly version you should load [`unpoly-migrate.js`](https://unpoly.com/changes/upgrading) to enable deprecated APIs. Also see below for an [overview of breaking changes](#overview-of-breaking-changes).
29
+
30
+ ### Change overview
31
+
32
+ #### Less need for boilerplate configuration
33
+
34
+ - Fragment links often replace the primary content element of your application layout. For this purpose you can now define [default targets](/up-main) that are automatically updated when no target selector is given.
35
+ - Unpoly can be configured to [handle all links and forms](/handling-everything), without any `[up-...]` attributes.
36
+ - We have examined many real-world Unpoly apps for repetitive configuration and made these options the new default.
37
+
38
+ #### New Layer API
39
+
40
+ - A new [layer API](/up.layer) replaces modals and popups.
41
+ - Layers can be stacked infinitely.
42
+ - Layers are fully isolated, meaning a screen in one layer will not accidentally see elements or events from another layer. For instance, [fragment links](/up.link) will only update elements from the [current layer](/up.layer.current) unless you [explicitly target another layer](/layer-option).
43
+ - A variety of [overlay modes](/layer-terminology) are supported, such as modal dialogs, popup overlays or drawers. You may [customize their appearance and behavior](/customizing-overlays).
44
+
45
+ #### Subinteractions
46
+
47
+ - Overlays allow you to break up a complex screen into [subinteractions](/subinteractions).
48
+ - Subinteractions take place in overlays and may span one or many pages. The original screen remains open in the background.
49
+ - Once the subinteraction is *done*, the overlay is [closed](/closing-overlays) and a result value is communicated back to the parent layer.
50
+
51
+ #### Navigation intent
52
+
53
+ - You can now define whether a framgent update constitutes a user navigation. Switching screens needs other defaults than updating a tiny box.
54
+ - User navigation aborts earlier requests, fixing race conditions on slow connections.
55
+
56
+ #### Accessibility
57
+
58
+ - New overlays are focused automatically and trap focus in a cycle. Closing the overlay re-focuses the link that opened it.
59
+ - Focus is automatically managed when rendering major new content. A new [`[up-focus]` attribute](/focus-option) allows
60
+ you to explicitely move the user's focus as you update fragments.
61
+ - Keyboard navigation is supported everywhere.
62
+ - Focus, selection and scroll positions are preserved within an updated fragment.
63
+
64
+ #### Reworked Bootstrap integration
65
+
66
+ - The Bootstrap integration is now minimal and as unopinionated as possible. Little to no Bootstrap CSS is overridden.
67
+ - Bootstrap versions 3, 4 and 5 are now supported.
68
+
69
+ #### Quality of live improvements
70
+
71
+ - Unpoly now ships with a bandwidth-friendly [polling implementation](/up-poll) that handles many edge cases.
72
+ - The position of a clicked link is considered when deciding which element to replace. If possible, Unpoly will update an selector in the vicinity of the link that triggered the fragment update. This helps with multiple self-contained components (with the same selector) on the same page.
73
+ - The [log](/up.log) output is more much more compact and has a calmer formatting.
74
+ - New fragments are no longer revealed by default. Instead Unpoly scrolls to the top when the [main target](/up-main) has changed, but does not scroll otherwise.
75
+ - History is no longer changed by default. Instead Unpoly updates history only when a [main target](/up-main) has changed.
76
+ - All scroll-related options have been unified in a single [`[up-scroll]` attribute](/scroll-option).
77
+ - Many optimizations have been made to preserve bandwidth on slow connections. For example, Unpoly stops [preloading](/up-preload) and [polling](/up-poll) whenthe connection has high latency or low throughput.
78
+ - The client-side cache can be carefully managed by both the client and server.
79
+ - Unpoly 1 had many functions for updating fragments (`up.replace()`, `up.extract()`, `up.modal.extract()`, etc.). Unpoly 2 has unified these into a single function `up.render()`.
80
+ - Event handlers to `up:link:follow`, `up:form:submit` etc. may change the render options for the coming fragment update.
81
+ - Added more options to handle [unexpected server responses](/server-errors), including the new `up:fragment:loaded` event.
82
+
83
+ #### Extended server protocol
84
+
85
+ The optional server protocol has been extended with additional headers that the server may use to interact with the frontend. For example:
86
+
87
+ - The server may [emit events on the frontend](/X-Up-Events).
88
+ - The server may [close overlays](/X-Up-Accept).
89
+ - The server may [change the render target](/X-Up-Target) for a fragment update.
90
+
91
+ See `up.protocol` for a full list of features.
92
+
93
+ If you are using Ruby on Rails, the new protocol is already implemented by the [`unpoly-rails`](https://rubygems.org/gems/unpoly-rails) gem.
94
+
95
+ If you are using Elixir / Phoenix, the new protocol is already implemented by the [`ex_unpoly`](https://hex.pm/packages/ex_unpoly) package.
96
+
97
+
98
+ ### Overview of breaking changes
99
+
100
+ Please use [`unpoly-migrate.js`](/changes/upgrading) for a very smooth upgrade process from Unpoly 0.x or 1.x to Unpoly 2.0.
101
+
102
+ By loading <code>unpoly-migrate.js</code>, calls to most old APIs will be forwarded to the new version. A deprecation notice will be logged to your browser console. This way you can upgrade Unpoly, revive your application with a few changes, then replace deprecated API calls under green tests.
103
+
104
+ There's a short list of changes that we cannot fix with aliases.
105
+
106
+ #### Overlays (modals, popups) have different HTML
107
+
108
+ But it's similar. E.g. `<div class="modal">` becomes `<up-modal>`.
109
+
110
+ #### Unpoly only sees the current layer
111
+
112
+ You can target other layers with `{ layer: 'any' }`.
113
+
114
+ #### Async functions no longer wait for animations
115
+
116
+ You might or might not notice. In cases where you absolutely do need to wait, an `{ onFinished }` callback can be used.
117
+
118
+ #### Tooltips are no longer built-in
119
+
120
+ But there are a million better libraries.
121
+
122
+
123
+ ### Unpoly 1 maintenance
124
+
125
+ With the release of Unpoly we're ending maintenance of Unpoly 1. Expect little to no changes to Unpoly 1 in the future. GitHub issues that have been fixed in Unpoly 2 will be closed.
126
+
127
+ The legacy documentation for Unpoly 1.x has been archived to <https://v1.unpoly.com>.
128
+
60
129
 
61
130
 
62
131
  1.0.0
63
132
  -----
64
133
 
65
- - TODO
134
+ For six years Unpoly has been released under a 0.x version number. To establish the maturity and stability of the project, we're releasing today's version as 1.0.0.
135
+
136
+ There are only three changes from 0.62.1:
137
+
138
+ - Fix a bug where `up.util.escapeHTML()`` would not escape single quotes.
139
+ - Unpoly will no longer wait a JavaScript execution task to boot after `DOMContentLoaded`. This may improve the stability of test suites that previously interacted with the page too soon.
140
+ - You may now disable the Unpoly banner in the development console with `up.log.config.banner = false`. (change by @hfjallemark).
141
+
142
+ This is the last release of the 0.x API line. We're tracking its code in the [`1.x-stable`](https://github.com/unpoly/unpoly/tree/1.x-stable), but expect little to no changes in the future.
66
143
 
144
+ The next release will be [Unpoly 2](https://triskweline.de/unpoly2-slides). It will include major (but mostly backwards compatible) renovations to its API, unlocking many use cases that were not possible with Unpoly 1.
67
145
 
68
146
 
69
147
  0.62.1
data/README.md CHANGED
@@ -35,6 +35,7 @@ Install dependencies for tests:
35
35
 
36
36
  - Install Ruby 2.3.8
37
37
  - Install Bundler by running `gem install bundler`
38
+ - Install Node.js (required for building the library)
38
39
  - `cd` into `spec_app`
39
40
  - Install dependencies by running `bundle install`
40
41
 
@@ -52,11 +53,9 @@ To run RSpec tests for the `unpoly-rails` gem:
52
53
 
53
54
  ### Making a new release
54
55
 
55
- We are currently feeding four release channels:
56
+ We are currently feeding two release channels:
56
57
 
57
- - Manual download from GitHub
58
58
  - npm
59
- - Bower (which is based on Git and version tags)
60
59
  - Rubygems (as the `unpoly-rails` gem)
61
60
 
62
61
  We always release to all channel simultaneously.
@@ -300,6 +300,43 @@ Returns the first descendant element matching the given selector.
300
300
  return !event.defaultPrevented;
301
301
  };
302
302
 
303
+ }).call(this);
304
+ (function() {
305
+ var e, u;
306
+
307
+ u = up.util;
308
+
309
+ e = up.element;
310
+
311
+ up.migrate.postCompile = function(elements, compiler) {
312
+ var element, i, keepValue, len, results, value;
313
+ if (keepValue = compiler.keep) {
314
+ up.migrate.warn('The { keep: true } option for up.compiler() has been removed. Have the compiler set [up-keep] attribute instead.');
315
+ value = u.isString(keepValue) ? keepValue : '';
316
+ results = [];
317
+ for (i = 0, len = elements.length; i < len; i++) {
318
+ element = elements[i];
319
+ results.push(element.setAttribute('up-keep', value));
320
+ }
321
+ return results;
322
+ }
323
+ };
324
+
325
+ up.migrate.targetMacro = function(queryAttr, fixedResultAttrs, callback) {
326
+ return up.macro("[" + queryAttr + "]", function(link) {
327
+ var optionalTarget, resultAttrs;
328
+ resultAttrs = u.copy(fixedResultAttrs);
329
+ if (optionalTarget = link.getAttribute(queryAttr)) {
330
+ resultAttrs['up-target'] = optionalTarget;
331
+ } else {
332
+ resultAttrs['up-follow'] = '';
333
+ }
334
+ e.setMissingAttrs(link, resultAttrs);
335
+ link.removeAttribute(queryAttr);
336
+ return typeof callback === "function" ? callback() : void 0;
337
+ });
338
+ };
339
+
303
340
  }).call(this);
304
341
 
305
342
  /***
@@ -538,6 +575,11 @@ Returns the first descendant element matching the given selector.
538
575
  up.migrate.renamedProperty(up.feedback.config, 'navs', 'navSelectors');
539
576
 
540
577
  }).call(this);
578
+
579
+ /***
580
+ @module up.link
581
+ */
582
+
541
583
  (function() {
542
584
  up.migrate.parseFollowOptions = function(parser) {
543
585
  parser.string('flavor');
@@ -549,6 +591,42 @@ Returns the first descendant element matching the given selector.
549
591
  return parser.boolean('restoreScroll');
550
592
  };
551
593
 
594
+
595
+ /***
596
+ [Follows](/up.follow) this link as fast as possible.
597
+
598
+ This is done by:
599
+
600
+ - [Following the link through AJAX](/a-up-follow) instead of a full page load
601
+ - [Preloading the link's destination URL](/a-up-preload)
602
+ - [Triggering the link on `mousedown`](/a-up-instant) instead of on `click`
603
+
604
+ \#\#\# Example
605
+
606
+ Use `[up-dash]` like this:
607
+
608
+ <a href="/users" up-dash=".main">User list</a>
609
+
610
+ This is shorthand for:
611
+
612
+ <a href="/users" up-target=".main" up-instant up-preload>User list</a>
613
+
614
+ @selector a[up-dash]
615
+ @param [up-dash='body']
616
+ The CSS selector to replace
617
+
618
+ Inside the CSS selector you may refer to this link as `&` ([like in Sass](https://sass-lang.com/documentation/file.SASS_REFERENCE.html#parent-selector)).
619
+ @deprecated
620
+ To accelerate all links use `up.link.config.instantSelectors` and `up.link.config.preloadSelectors`.
621
+ */
622
+
623
+ up.migrate.targetMacro('up-dash', {
624
+ 'up-preload': '',
625
+ 'up-instant': ''
626
+ }, function() {
627
+ return up.migrate.deprecated('a[up-dash]', 'up.link.config.instantSelectors or up.link.config.preloadSelectors');
628
+ });
629
+
552
630
  }).call(this);
553
631
 
554
632
  /***
@@ -826,10 +904,10 @@ Returns the first descendant element matching the given selector.
826
904
  @param {string} up-modal
827
905
  The CSS selector that will be extracted from the response and displayed in a modal dialog.
828
906
  @deprecated
829
- Use `a[up-layer=modal]` instead.
907
+ Use `a[up-layer="new modal"]` instead.
830
908
  */
831
909
 
832
- up.link.targetMacro('up-modal', {
910
+ up.migrate.targetMacro('up-modal', {
833
911
  'up-layer': 'new modal'
834
912
  }, function() {
835
913
  return up.migrate.deprecated('a[up-modal]', 'a[up-layer="new modal"]');
@@ -846,16 +924,21 @@ Returns the first descendant element matching the given selector.
846
924
  @param {string} up-drawer
847
925
  The CSS selector that will be extracted from the response and displayed in a modal dialog.
848
926
  @deprecated
849
- Use `a[up-layer=drawer]` instead.
927
+ Use `a[up-layer="new drawer"]` instead.
850
928
  */
851
929
 
852
- up.link.targetMacro('up-drawer', {
930
+ up.migrate.targetMacro('up-drawer', {
853
931
  'up-layer': 'new drawer'
854
932
  }, function() {
855
933
  return up.migrate.deprecated('a[up-drawer]', 'a[up-layer="new drawer"]');
856
934
  });
857
935
 
858
936
  }).call(this);
937
+
938
+ /***
939
+ @module up.layer
940
+ */
941
+
859
942
  (function() {
860
943
  var e, u;
861
944
 
@@ -987,7 +1070,7 @@ Returns the first descendant element matching the given selector.
987
1070
 
988
1071
  up.migrate.renamedEvent('up:popup:closed', 'up:layer:dismissed');
989
1072
 
990
- up.link.targetMacro('up-popup', {
1073
+ up.migrate.targetMacro('up-popup', {
991
1074
  'up-layer': 'new popup'
992
1075
  }, function() {
993
1076
  return up.migrate.deprecated('[up-popup]', '[up-layer="new popup"]');
@@ -1060,15 +1143,6 @@ This feature is now deprecated.
1060
1143
 
1061
1144
  up.migrate.renamedProperty(up.network.config, 'slowDelay', 'badResponseTime');
1062
1145
 
1063
- up.migrate.handleNetworkPreloadArgs = function() {
1064
- var args, ref;
1065
- args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1066
- if (u.isElementish(args[0])) {
1067
- up.migrate.warn('up.proxy.preload(link) has been renamed to up.link.preload(link)');
1068
- return (ref = up.link).preload.apply(ref, args);
1069
- }
1070
- };
1071
-
1072
1146
  up.migrate.handleRequestOptions = function(options) {
1073
1147
  return up.migrate.fixKey(options, 'data', 'params');
1074
1148
  };
@@ -1081,11 +1155,13 @@ This feature is now deprecated.
1081
1155
 
1082
1156
  \#\#\# Example
1083
1157
 
1084
- up.request('/search', { params: { query: 'sunshine' } }).then(function(text) {
1085
- console.log('The response text is %o', text)
1086
- }).catch(function() {
1087
- console.error('The request failed')
1088
- })
1158
+ ```
1159
+ up.ajax('/search', { params: { query: 'sunshine' } }).then(function(text) {
1160
+ console.log('The response text is %o', text)
1161
+ }).catch(function() {
1162
+ console.error('The request failed')
1163
+ })
1164
+ ```
1089
1165
 
1090
1166
  @function up.ajax
1091
1167
  @param {string} [url]
@@ -1124,6 +1200,13 @@ This feature is now deprecated.
1124
1200
  return up.cache.clear();
1125
1201
  };
1126
1202
 
1203
+ up.network.preload = function() {
1204
+ var args, ref;
1205
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1206
+ up.migrate.deprecated('up.proxy.preload(link)', 'up.link.preload(link)');
1207
+ return (ref = up.link).preload.apply(ref, args);
1208
+ };
1209
+
1127
1210
 
1128
1211
  /***
1129
1212
  @class up.Request
@@ -1 +1 @@
1
- (function(){up.framework.startExtension()}).call(this),function(){var u,p,e,t,r,a,n,i,o,l,c,s,d,m,g=[].slice;u=up.util,up.migrate=(p=new up.Config(function(){return{logLevel:"warn"}}),c=function(e,t,r){var a;return a=function(){return d("Property { %s } has been renamed to { %s } (found in %o)",t,r,e)},Object.defineProperty(e,t,{get:function(){return a(),this[r]},set:function(e){return a(),this[r]=e}})},a=function(e,t,r){if(u.isDefined(e[t]))return d("Property { %s } has been renamed to { %s } (found in %o)",t,r,e),u.renameKey(e,t,r)},o={},i=function(e,t){return o[e]=t},t=function(e){var t;return(t=o[e])?(d("Event "+e+" has been renamed to "+t),t):e},r=function(e){return u.uniq(u.map(e,t))},l=function(e,t){return Object.defineProperty(up,e,{get:function(){return d("up."+e+" has been renamed to up."+t),up[t]}})},m={},d=function(e){var t,r,a,n;if(a=e,t=2<=arguments.length?g.call(arguments,1):[],r=u.sprintf.apply(u,[a].concat(g.call(t))),!m[r])return m[r]=!0,(n=up.log)[p.logLevel].apply(n,["DEPRECATION",a].concat(g.call(t)))},e=function(e,t){return d(e+" has been deprecated. Use "+t+" instead.")},n=function(e){var t,r;return r=Promise.resolve(),t=r.then,r.then=function(){return d(e+" is now a sync function"),t.apply(this,arguments)},r},s=function(){return p.reset()},up.on("up:framework:reset",s),{deprecated:e,renamedPackage:l,renamedProperty:c,formerlyAsync:n,renamedEvent:i,fixEventTypes:r,fixKey:a,warn:d,loaded:!0,config:p})}.call(this),function(){var a=[].slice;up.util.only=function(e){var t,r;return r=e,t=2<=arguments.length?a.call(arguments,1):[],up.migrate.deprecated("up.util.only(object, ...keys)","up.util.pick(object, keys)"),up.util.pick(r,t)},up.util.except=function(e){var t,r;return r=e,t=2<=arguments.length?a.call(arguments,1):[],up.migrate.deprecated("up.util.except(object, ...keys)","up.util.omit(object, keys)"),up.util.omit(r,t)},up.util.parseUrl=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.parseUrl() has been renamed to up.util.parseURL()"),(t=up.util).parseURL.apply(t,e)},up.util.any=function(){var e;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.any() has been renamed to up.util.some()"),some.apply(null,e)},up.util.all=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.all() has been renamed to up.util.every()"),(t=up.util).every.apply(t,e)},up.util.detect=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.detect() has been renamed to up.util.find()"),(t=up.util).find.apply(t,e)},up.util.select=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.select() has been renamed to up.util.filter()"),(t=up.util).filter.apply(t,e)},up.util.setTimer=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.setTimer() has been renamed to up.util.timer()"),(t=up.util).timer.apply(t,e)},up.util.escapeHtml=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.deprecated("up.util.escapeHtml","up.util.escapeHTML"),(t=up.util).escapeHTML.apply(t,e)},up.util.selectorForElement=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.selectorForElement() has been renamed to up.fragment.toTarget()"),(t=up.fragment).toTarget.apply(t,e)},up.util.nextFrame=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.nextFrame() has been renamed to up.util.task()"),(t=up.util).task.apply(t,e)}}.call(this),function(){var r=[].slice;up.element.first=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.element.first()","up.element.get()"),(t=up.element).get.apply(t,e)},up.element.createFromHtml=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.element.createFromHtml","up.element.createFromHTML"),(t=up.element).createFromHTML.apply(t,e)}}.call(this),function(){var t=[].slice;up.migrate.renamedPackage("bus","event"),up.event.nobodyPrevents=function(){var e;return e=1<=arguments.length?t.call(arguments,0):[],up.migrate.deprecated("up.event.nobodyPrevents(type)","!up.emit(type).defaultPrevented"),!up.emit.apply(up,e).defaultPrevented}}.call(this),function(){up.migrate.renamedProperty(up.form.config,"fields","fieldSelectors"),up.migrate.renamedProperty(up.form.config,"submitButtons","submitButtonSelectors")}.call(this),function(){var p,r=[].slice;p=up.util,up.migrate.renamedPackage("flow","fragment"),up.migrate.renamedPackage("dom","fragment"),up.migrate.renamedProperty(up.fragment.config,"fallbacks","mainTargets"),up.migrate.handleResponseDocOptions=function(e){return up.migrate.fixKey(e,"html","document")},up.replace=function(e,t,r){return up.migrate.deprecated("up.replace(target, url)","up.navigate(target, { url })"),up.navigate(p.merge(r,{target:e,url:t}))},up.extract=function(e,t,r){return up.migrate.deprecated("up.extract(target, document)","up.navigate(target, { document })"),up.navigate(p.merge(r,{target:e,document:t}))},up.fragment.first=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.fragment.first()","up.fragment.get()"),(t=up.fragment).get.apply(t,e)},up.first=up.fragment.first,up.migrate.handleScrollOptions=function(e){if(p.isUndefined(e.scroll)&&(p.isString(e.reveal)?(up.migrate.deprecated("Option { reveal: '"+e.reveal+"' }","{ scroll: '"+e.reveal+"' }"),e.scroll=e.reveal):!0===e.reveal?(up.migrate.deprecated("Option { reveal: true }","{ scroll: 'target' }"),e.scroll="target"):!1===e.reveal&&(up.migrate.deprecated("Option { reveal: false }","{ scroll: false }"),e.scroll=!1),p.isDefined(e.resetScroll)&&(up.migrate.deprecated("Option { resetScroll: true }","{ scroll: 'reset' }"),e.scroll="teset"),p.isDefined(e.restoreScroll)))return up.migrate.deprecated("Option { restoreScroll: true }","{ scroll: 'restore' }"),e.scroll="restore"},up.migrate.handleHistoryOption=function(e){if(p.isString(e.history)&&"auto"!==e.history)return up.migrate.warn("Passing a URL as { history } option is deprecated. Pass it as { location } instead."),e.location=e.history,e.history="auto"},up.migrate.handleRenderOptions=function(e){var t,r,a,n,u;for(up.migrate.handleHistoryOption(e),u=[],t=0,r=(n=["target","origin"]).length;t<r;t++)a=n[t],p.isJQuery(e[a])?(up.migrate.warn("Passing a jQuery collection as { %s } is deprecated. Pass it as a native element instead.",a),u.push(e[a]=up.element.get(e[a]))):u.push(void 0);return u}}.call(this),function(){up.migrate.renamedProperty(up.history.config,"popTargets","restoreTargets"),up.history.url=function(){return up.migrate.deprecated("up.history.url()","up.history.location"),up.history.location},up.migrate.renamedEvent("up:history:push","up:location:changed"),up.migrate.renamedEvent("up:history:pushed","up:location:changed"),up.migrate.renamedEvent("up:history:restore","up:location:changed"),up.migrate.renamedEvent("up:history:restored","up:location:changed"),up.migrate.renamedEvent("up:history:replaced","up:location:changed")}.call(this),function(){up.migrate.renamedPackage("navigation","feedback"),up.migrate.renamedProperty(up.feedback.config,"navs","navSelectors")}.call(this),function(){up.migrate.parseFollowOptions=function(e){return e.string("flavor"),e.string("width"),e.string("height"),e["boolean"]("closable"),e.booleanOrString("reveal"),e["boolean"]("resetScroll"),e["boolean"]("restoreScroll")}}.call(this),function(){up.migrate.handleLayerOptions=function(e){var t,r,a,n;for(up.migrate.fixKey(e,"flavor","mode"),up.migrate.fixKey(e,"closable","dismissable"),up.migrate.fixKey(e,"closeLabel","dismissLabel"),r=0,a=(n=["width","maxWidth","height"]).length;r<a;r++)e[t=n[r]]&&up.migrate.warn("Layer option { "+t+" } has been removed. Use { size } or { class } instead.");if(e.sticky&&up.migrate.warn("Layer option { sticky } has been removed. Give links an [up-peel=false] attribute to prevent layer dismissal on click."),e.template&&up.migrate.warn("Layer option { template } has been removed. Use { class } or modify the layer HTML on up:layer:open."),"page"===e.layer&&(up.migrate.warn("Option { layer: 'page' } has been renamed to { layer: 'root' }."),e.layer="root"),"modal"===e.layer||"popup"===e.layer)return up.migrate.warn("Option { layer: '"+e.layer+"' } has been removed. Did you mean { layer: 'overlay' }?"),e.layer="overlay"},up.migrate.handleTetherOptions=function(e){var t,r,a;if(r=(a=e.position.split("-"))[0],t=a[1])return up.migrate.warn("The position value %o is deprecated. Use %o instead.",e.position,{position:r,align:t}),e.position=r,e.align=t},up.migrate.registerLayerCloser=function(r){return r.registerClickCloser("up-close",function(e,t){return up.migrate.deprecated("[up-close]","[up-dismiss]"),r.dismiss(e,t)})},up.migrate.handleLayerConfig=function(e){return up.migrate.fixKey(e,"history","historyVisible")}}.call(this),function(){var e,a;a=up.util,e=new Error("up.modal.flavors has been removed without direct replacement. You may give new layers a { class } or modify layer elements on up:layer:open."),up.modal=a.literal({visit:function(e,t){return null==t&&(t={}),up.migrate.deprecated("up.modal.visit(url)",'up.layer.open({ url, mode: "modal" })'),up.layer.open(a.merge(t,{url:e,mode:"modal"}))},follow:function(e,t){return null==t&&(t={}),up.migrate.deprecated("up.modal.follow(link)",'up.follow(link, { layer: "modal" })'),up.follow(e,a.merge(t,{layer:"modal"}))},extract:function(e,t,r){return null==r&&(r={}),up.migrate.deprecated("up.modal.extract(target, document)",'up.layer.open({ document, mode: "modal" })'),up.layer.open(a.merge(r,{target:e,html:t,layer:"modal"}))},close:function(e){return null==e&&(e={}),up.migrate.deprecated("up.modal.close()","up.layer.dismiss()"),up.layer.dismiss(null,e),up.migrate.formerlyAsync("up.layer.dismiss()")},url:function(){return up.migrate.deprecated("up.modal.url()","up.layer.location"),up.layer.location},coveredUrl:function(){var e;return up.migrate.deprecated("up.modal.coveredUrl()","up.layer.parent.location"),null!=(e=up.layer.parent)?e.location:void 0},get_config:function(){return up.migrate.deprecated("up.modal.config","up.layer.config.modal"),up.layer.config.modal},contains:function(e){return up.migrate.deprecated("up.modal.contains()","up.layer.contains()"),up.layer.contains(e)},isOpen:function(){return up.migrate.deprecated("up.modal.isOpen()","up.layer.isOverlay()"),up.layer.isOverlay()},get_flavors:function(){throw e},flavor:function(){throw e}}),up.migrate.renamedEvent("up:modal:open","up:layer:open"),up.migrate.renamedEvent("up:modal:opened","up:layer:opened"),up.migrate.renamedEvent("up:modal:close","up:layer:dismiss"),up.migrate.renamedEvent("up:modal:closed","up:layer:dismissed"),up.link.targetMacro("up-modal",{"up-layer":"new modal"},function(){return up.migrate.deprecated("a[up-modal]",'a[up-layer="new modal"]')}),up.link.targetMacro("up-drawer",{"up-layer":"new drawer"},function(){return up.migrate.deprecated("a[up-drawer]",'a[up-layer="new drawer"]')})}.call(this),function(){var r;r=up.util,up.element,up.popup=r.literal({attach:function(e,t){return null==t&&(t={}),e=up.fragment.get(e),up.migrate.deprecated("up.popup.attach(origin)","up.layer.open({ origin, layer: 'popup' })"),up.layer.open(r.merge(t,{origin:e,layer:"popup"}))},close:function(e){return null==e&&(e={}),up.migrate.deprecated("up.popup.close()","up.layer.dismiss()"),up.layer.dismiss(null,e)},url:function(){return up.migrate.deprecated("up.popup.url()","up.layer.location"),up.layer.location},coveredUrl:function(){var e;return up.migrate.deprecated("up.popup.coveredUrl()","up.layer.parent.location"),null!=(e=up.layer.parent)?e.location:void 0},get_config:function(){return up.migrate.deprecated("up.popup.config","up.layer.config.popup"),up.layer.config.popup},contains:function(e){return up.migrate.deprecated("up.popup.contains()","up.layer.contains()"),up.layer.contains(e)},isOpen:function(){return up.migrate.deprecated("up.popup.isOpen()","up.layer.isOverlay()"),up.layer.isOverlay()},sync:function(){return up.migrate.deprecated("up.popup.sync()","up.layer.sync()"),up.layer.sync()}}),up.migrate.renamedEvent("up:popup:open","up:layer:open"),up.migrate.renamedEvent("up:popup:opened","up:layer:opened"),up.migrate.renamedEvent("up:popup:close","up:layer:dismiss"),up.migrate.renamedEvent("up:popup:closed","up:layer:dismissed"),up.link.targetMacro("up-popup",{"up-layer":"new popup"},function(){return up.migrate.deprecated("[up-popup]",'[up-layer="new popup"]')})}.call(this),function(){up.tooltip=up.macro("[up-tooltip]",function(e){return up.migrate.warn("[up-tooltip] has been deprecated. A [title] was set instead."),up.element.setMissingAttr(e,"title",e.getAttribute("up-tooltip"))})}.call(this),function(){var t,r,a=[].slice;r=up.util,up.migrate.renamedPackage("proxy","network"),up.migrate.renamedEvent("up:proxy:load","up:request:load"),up.migrate.renamedEvent("up:proxy:received","up:request:loaded"),up.migrate.renamedEvent("up:proxy:loaded","up:request:loaded"),up.migrate.renamedEvent("up:proxy:fatal","up:request:fatal"),up.migrate.renamedEvent("up:proxy:aborted","up:request:aborted"),up.migrate.renamedEvent("up:proxy:slow","up:request:late"),up.migrate.renamedEvent("up:proxy:recover","up:request:recover"),t=function(){return up.migrate.deprecated("up.proxy.config.preloadDelay","up.link.config.preloadDelay")},Object.defineProperty(up.network.config,"preloadDelay",{get:function(){return t(),up.link.config.preloadDelay},set:function(e){return t(),up.link.config.preloadDelay=e}}),up.migrate.renamedProperty(up.network.config,"maxRequests","concurrency"),up.migrate.renamedProperty(up.network.config,"slowDelay","badResponseTime"),up.migrate.handleNetworkPreloadArgs=function(){var e,t;if(e=1<=arguments.length?a.call(arguments,0):[],r.isElementish(e[0]))return up.migrate.warn("up.proxy.preload(link) has been renamed to up.link.preload(link)"),(t=up.link).preload.apply(t,e)},up.migrate.handleRequestOptions=function(e){return up.migrate.fixKey(e,"data","params")},up.ajax=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.deprecated("up.ajax()","up.request()"),t=function(e){return e.text},up.request.apply(up,e).then(t)},up.network.clear=function(){return up.migrate.deprecated("up.proxy.clear()","up.cache.clear()"),up.cache.clear()},up.Request.prototype.navigate=function(){return up.migrate.deprecated("up.Request#navigate()","up.Request#loadPage()"),this.loadPage()},up.Response.prototype.isSuccess=function(){return up.migrate.deprecated("up.Response#isSuccess()","up.Response#ok"),this.ok},up.Response.prototype.isError=function(){return up.migrate.deprecated("up.Response#isError()","!up.Response#ok"),!this.ok}}.call(this),function(){up.migrate.renamedProperty(up.radio.config,"hungry","hungrySelectors")}.call(this),function(){var r=[].slice;up.migrate.renamedPackage("layout","viewport"),up.migrate.renamedProperty(up.viewport.config,"viewports","viewportSelectors"),up.migrate.renamedProperty(up.viewport.config,"snap","revealSnap"),up.viewport.closest=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.viewport.closest()","up.viewport.get()"),(t=up.viewport).get.apply(t,e)}}.call(this),function(){up.framework.stopExtension()}.call(this),function(){}.call(this);
1
+ (function(){up.framework.startExtension()}).call(this),function(){var u,p,e,t,r,a,n,i,o,l,c,s,d,m,g=[].slice;u=up.util,up.migrate=(p=new up.Config(function(){return{logLevel:"warn"}}),c=function(e,t,r){var a;return a=function(){return d("Property { %s } has been renamed to { %s } (found in %o)",t,r,e)},Object.defineProperty(e,t,{get:function(){return a(),this[r]},set:function(e){return a(),this[r]=e}})},a=function(e,t,r){if(u.isDefined(e[t]))return d("Property { %s } has been renamed to { %s } (found in %o)",t,r,e),u.renameKey(e,t,r)},o={},i=function(e,t){return o[e]=t},t=function(e){var t;return(t=o[e])?(d("Event "+e+" has been renamed to "+t),t):e},r=function(e){return u.uniq(u.map(e,t))},l=function(e,t){return Object.defineProperty(up,e,{get:function(){return d("up."+e+" has been renamed to up."+t),up[t]}})},m={},d=function(e){var t,r,a,n;if(a=e,t=2<=arguments.length?g.call(arguments,1):[],r=u.sprintf.apply(u,[a].concat(g.call(t))),!m[r])return m[r]=!0,(n=up.log)[p.logLevel].apply(n,["DEPRECATION",a].concat(g.call(t)))},e=function(e,t){return d(e+" has been deprecated. Use "+t+" instead.")},n=function(e){var t,r;return r=Promise.resolve(),t=r.then,r.then=function(){return d(e+" is now a sync function"),t.apply(this,arguments)},r},s=function(){return p.reset()},up.on("up:framework:reset",s),{deprecated:e,renamedPackage:l,renamedProperty:c,formerlyAsync:n,renamedEvent:i,fixEventTypes:r,fixKey:a,warn:d,loaded:!0,config:p})}.call(this),function(){var a=[].slice;up.util.only=function(e){var t,r;return r=e,t=2<=arguments.length?a.call(arguments,1):[],up.migrate.deprecated("up.util.only(object, ...keys)","up.util.pick(object, keys)"),up.util.pick(r,t)},up.util.except=function(e){var t,r;return r=e,t=2<=arguments.length?a.call(arguments,1):[],up.migrate.deprecated("up.util.except(object, ...keys)","up.util.omit(object, keys)"),up.util.omit(r,t)},up.util.parseUrl=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.parseUrl() has been renamed to up.util.parseURL()"),(t=up.util).parseURL.apply(t,e)},up.util.any=function(){var e;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.any() has been renamed to up.util.some()"),some.apply(null,e)},up.util.all=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.all() has been renamed to up.util.every()"),(t=up.util).every.apply(t,e)},up.util.detect=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.detect() has been renamed to up.util.find()"),(t=up.util).find.apply(t,e)},up.util.select=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.select() has been renamed to up.util.filter()"),(t=up.util).filter.apply(t,e)},up.util.setTimer=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.setTimer() has been renamed to up.util.timer()"),(t=up.util).timer.apply(t,e)},up.util.escapeHtml=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.deprecated("up.util.escapeHtml","up.util.escapeHTML"),(t=up.util).escapeHTML.apply(t,e)},up.util.selectorForElement=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.selectorForElement() has been renamed to up.fragment.toTarget()"),(t=up.fragment).toTarget.apply(t,e)},up.util.nextFrame=function(){var e,t;return e=1<=arguments.length?a.call(arguments,0):[],up.migrate.warn("up.util.nextFrame() has been renamed to up.util.task()"),(t=up.util).task.apply(t,e)}}.call(this),function(){var r=[].slice;up.element.first=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.element.first()","up.element.get()"),(t=up.element).get.apply(t,e)},up.element.createFromHtml=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.element.createFromHtml","up.element.createFromHTML"),(t=up.element).createFromHTML.apply(t,e)}}.call(this),function(){var t=[].slice;up.migrate.renamedPackage("bus","event"),up.event.nobodyPrevents=function(){var e;return e=1<=arguments.length?t.call(arguments,0):[],up.migrate.deprecated("up.event.nobodyPrevents(type)","!up.emit(type).defaultPrevented"),!up.emit.apply(up,e).defaultPrevented}}.call(this),function(){var p,o;o=up.util,p=up.element,up.migrate.postCompile=function(e,t){var r,a,n,u,p,i;if(n=t.keep){for(up.migrate.warn("The { keep: true } option for up.compiler() has been removed. Have the compiler set [up-keep] attribute instead."),i=o.isString(n)?n:"",p=[],a=0,u=e.length;a<u;a++)r=e[a],p.push(r.setAttribute("up-keep",i));return p}},up.migrate.targetMacro=function(a,n,u){return up.macro("["+a+"]",function(e){var t,r;return r=o.copy(n),(t=e.getAttribute(a))?r["up-target"]=t:r["up-follow"]="",p.setMissingAttrs(e,r),e.removeAttribute(a),"function"==typeof u?u():void 0})}}.call(this),function(){up.migrate.renamedProperty(up.form.config,"fields","fieldSelectors"),up.migrate.renamedProperty(up.form.config,"submitButtons","submitButtonSelectors")}.call(this),function(){var p,r=[].slice;p=up.util,up.migrate.renamedPackage("flow","fragment"),up.migrate.renamedPackage("dom","fragment"),up.migrate.renamedProperty(up.fragment.config,"fallbacks","mainTargets"),up.migrate.handleResponseDocOptions=function(e){return up.migrate.fixKey(e,"html","document")},up.replace=function(e,t,r){return up.migrate.deprecated("up.replace(target, url)","up.navigate(target, { url })"),up.navigate(p.merge(r,{target:e,url:t}))},up.extract=function(e,t,r){return up.migrate.deprecated("up.extract(target, document)","up.navigate(target, { document })"),up.navigate(p.merge(r,{target:e,document:t}))},up.fragment.first=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.fragment.first()","up.fragment.get()"),(t=up.fragment).get.apply(t,e)},up.first=up.fragment.first,up.migrate.handleScrollOptions=function(e){if(p.isUndefined(e.scroll)&&(p.isString(e.reveal)?(up.migrate.deprecated("Option { reveal: '"+e.reveal+"' }","{ scroll: '"+e.reveal+"' }"),e.scroll=e.reveal):!0===e.reveal?(up.migrate.deprecated("Option { reveal: true }","{ scroll: 'target' }"),e.scroll="target"):!1===e.reveal&&(up.migrate.deprecated("Option { reveal: false }","{ scroll: false }"),e.scroll=!1),p.isDefined(e.resetScroll)&&(up.migrate.deprecated("Option { resetScroll: true }","{ scroll: 'reset' }"),e.scroll="teset"),p.isDefined(e.restoreScroll)))return up.migrate.deprecated("Option { restoreScroll: true }","{ scroll: 'restore' }"),e.scroll="restore"},up.migrate.handleHistoryOption=function(e){if(p.isString(e.history)&&"auto"!==e.history)return up.migrate.warn("Passing a URL as { history } option is deprecated. Pass it as { location } instead."),e.location=e.history,e.history="auto"},up.migrate.handleRenderOptions=function(e){var t,r,a,n,u;for(up.migrate.handleHistoryOption(e),u=[],t=0,r=(n=["target","origin"]).length;t<r;t++)a=n[t],p.isJQuery(e[a])?(up.migrate.warn("Passing a jQuery collection as { %s } is deprecated. Pass it as a native element instead.",a),u.push(e[a]=up.element.get(e[a]))):u.push(void 0);return u}}.call(this),function(){up.migrate.renamedProperty(up.history.config,"popTargets","restoreTargets"),up.history.url=function(){return up.migrate.deprecated("up.history.url()","up.history.location"),up.history.location},up.migrate.renamedEvent("up:history:push","up:location:changed"),up.migrate.renamedEvent("up:history:pushed","up:location:changed"),up.migrate.renamedEvent("up:history:restore","up:location:changed"),up.migrate.renamedEvent("up:history:restored","up:location:changed"),up.migrate.renamedEvent("up:history:replaced","up:location:changed")}.call(this),function(){up.migrate.renamedPackage("navigation","feedback"),up.migrate.renamedProperty(up.feedback.config,"navs","navSelectors")}.call(this),function(){up.migrate.parseFollowOptions=function(e){return e.string("flavor"),e.string("width"),e.string("height"),e["boolean"]("closable"),e.booleanOrString("reveal"),e["boolean"]("resetScroll"),e["boolean"]("restoreScroll")},up.migrate.targetMacro("up-dash",{"up-preload":"","up-instant":""},function(){return up.migrate.deprecated("a[up-dash]","up.link.config.instantSelectors or up.link.config.preloadSelectors")})}.call(this),function(){up.migrate.handleLayerOptions=function(e){var t,r,a,n;for(up.migrate.fixKey(e,"flavor","mode"),up.migrate.fixKey(e,"closable","dismissable"),up.migrate.fixKey(e,"closeLabel","dismissLabel"),r=0,a=(n=["width","maxWidth","height"]).length;r<a;r++)e[t=n[r]]&&up.migrate.warn("Layer option { "+t+" } has been removed. Use { size } or { class } instead.");if(e.sticky&&up.migrate.warn("Layer option { sticky } has been removed. Give links an [up-peel=false] attribute to prevent layer dismissal on click."),e.template&&up.migrate.warn("Layer option { template } has been removed. Use { class } or modify the layer HTML on up:layer:open."),"page"===e.layer&&(up.migrate.warn("Option { layer: 'page' } has been renamed to { layer: 'root' }."),e.layer="root"),"modal"===e.layer||"popup"===e.layer)return up.migrate.warn("Option { layer: '"+e.layer+"' } has been removed. Did you mean { layer: 'overlay' }?"),e.layer="overlay"},up.migrate.handleTetherOptions=function(e){var t,r,a;if(r=(a=e.position.split("-"))[0],t=a[1])return up.migrate.warn("The position value %o is deprecated. Use %o instead.",e.position,{position:r,align:t}),e.position=r,e.align=t},up.migrate.registerLayerCloser=function(r){return r.registerClickCloser("up-close",function(e,t){return up.migrate.deprecated("[up-close]","[up-dismiss]"),r.dismiss(e,t)})},up.migrate.handleLayerConfig=function(e){return up.migrate.fixKey(e,"history","historyVisible")}}.call(this),function(){var e,a;a=up.util,e=new Error("up.modal.flavors has been removed without direct replacement. You may give new layers a { class } or modify layer elements on up:layer:open."),up.modal=a.literal({visit:function(e,t){return null==t&&(t={}),up.migrate.deprecated("up.modal.visit(url)",'up.layer.open({ url, mode: "modal" })'),up.layer.open(a.merge(t,{url:e,mode:"modal"}))},follow:function(e,t){return null==t&&(t={}),up.migrate.deprecated("up.modal.follow(link)",'up.follow(link, { layer: "modal" })'),up.follow(e,a.merge(t,{layer:"modal"}))},extract:function(e,t,r){return null==r&&(r={}),up.migrate.deprecated("up.modal.extract(target, document)",'up.layer.open({ document, mode: "modal" })'),up.layer.open(a.merge(r,{target:e,html:t,layer:"modal"}))},close:function(e){return null==e&&(e={}),up.migrate.deprecated("up.modal.close()","up.layer.dismiss()"),up.layer.dismiss(null,e),up.migrate.formerlyAsync("up.layer.dismiss()")},url:function(){return up.migrate.deprecated("up.modal.url()","up.layer.location"),up.layer.location},coveredUrl:function(){var e;return up.migrate.deprecated("up.modal.coveredUrl()","up.layer.parent.location"),null!=(e=up.layer.parent)?e.location:void 0},get_config:function(){return up.migrate.deprecated("up.modal.config","up.layer.config.modal"),up.layer.config.modal},contains:function(e){return up.migrate.deprecated("up.modal.contains()","up.layer.contains()"),up.layer.contains(e)},isOpen:function(){return up.migrate.deprecated("up.modal.isOpen()","up.layer.isOverlay()"),up.layer.isOverlay()},get_flavors:function(){throw e},flavor:function(){throw e}}),up.migrate.renamedEvent("up:modal:open","up:layer:open"),up.migrate.renamedEvent("up:modal:opened","up:layer:opened"),up.migrate.renamedEvent("up:modal:close","up:layer:dismiss"),up.migrate.renamedEvent("up:modal:closed","up:layer:dismissed"),up.migrate.targetMacro("up-modal",{"up-layer":"new modal"},function(){return up.migrate.deprecated("a[up-modal]",'a[up-layer="new modal"]')}),up.migrate.targetMacro("up-drawer",{"up-layer":"new drawer"},function(){return up.migrate.deprecated("a[up-drawer]",'a[up-layer="new drawer"]')})}.call(this),function(){var r;r=up.util,up.element,up.popup=r.literal({attach:function(e,t){return null==t&&(t={}),e=up.fragment.get(e),up.migrate.deprecated("up.popup.attach(origin)","up.layer.open({ origin, layer: 'popup' })"),up.layer.open(r.merge(t,{origin:e,layer:"popup"}))},close:function(e){return null==e&&(e={}),up.migrate.deprecated("up.popup.close()","up.layer.dismiss()"),up.layer.dismiss(null,e)},url:function(){return up.migrate.deprecated("up.popup.url()","up.layer.location"),up.layer.location},coveredUrl:function(){var e;return up.migrate.deprecated("up.popup.coveredUrl()","up.layer.parent.location"),null!=(e=up.layer.parent)?e.location:void 0},get_config:function(){return up.migrate.deprecated("up.popup.config","up.layer.config.popup"),up.layer.config.popup},contains:function(e){return up.migrate.deprecated("up.popup.contains()","up.layer.contains()"),up.layer.contains(e)},isOpen:function(){return up.migrate.deprecated("up.popup.isOpen()","up.layer.isOverlay()"),up.layer.isOverlay()},sync:function(){return up.migrate.deprecated("up.popup.sync()","up.layer.sync()"),up.layer.sync()}}),up.migrate.renamedEvent("up:popup:open","up:layer:open"),up.migrate.renamedEvent("up:popup:opened","up:layer:opened"),up.migrate.renamedEvent("up:popup:close","up:layer:dismiss"),up.migrate.renamedEvent("up:popup:closed","up:layer:dismissed"),up.migrate.targetMacro("up-popup",{"up-layer":"new popup"},function(){return up.migrate.deprecated("[up-popup]",'[up-layer="new popup"]')})}.call(this),function(){up.tooltip=up.macro("[up-tooltip]",function(e){return up.migrate.warn("[up-tooltip] has been deprecated. A [title] was set instead."),up.element.setMissingAttr(e,"title",e.getAttribute("up-tooltip"))})}.call(this),function(){var t,r=[].slice;up.util,up.migrate.renamedPackage("proxy","network"),up.migrate.renamedEvent("up:proxy:load","up:request:load"),up.migrate.renamedEvent("up:proxy:received","up:request:loaded"),up.migrate.renamedEvent("up:proxy:loaded","up:request:loaded"),up.migrate.renamedEvent("up:proxy:fatal","up:request:fatal"),up.migrate.renamedEvent("up:proxy:aborted","up:request:aborted"),up.migrate.renamedEvent("up:proxy:slow","up:request:late"),up.migrate.renamedEvent("up:proxy:recover","up:request:recover"),t=function(){return up.migrate.deprecated("up.proxy.config.preloadDelay","up.link.config.preloadDelay")},Object.defineProperty(up.network.config,"preloadDelay",{get:function(){return t(),up.link.config.preloadDelay},set:function(e){return t(),up.link.config.preloadDelay=e}}),up.migrate.renamedProperty(up.network.config,"maxRequests","concurrency"),up.migrate.renamedProperty(up.network.config,"slowDelay","badResponseTime"),up.migrate.handleRequestOptions=function(e){return up.migrate.fixKey(e,"data","params")},up.ajax=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.ajax()","up.request()"),t=function(e){return e.text},up.request.apply(up,e).then(t)},up.network.clear=function(){return up.migrate.deprecated("up.proxy.clear()","up.cache.clear()"),up.cache.clear()},up.network.preload=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.proxy.preload(link)","up.link.preload(link)"),(t=up.link).preload.apply(t,e)},up.Request.prototype.navigate=function(){return up.migrate.deprecated("up.Request#navigate()","up.Request#loadPage()"),this.loadPage()},up.Response.prototype.isSuccess=function(){return up.migrate.deprecated("up.Response#isSuccess()","up.Response#ok"),this.ok},up.Response.prototype.isError=function(){return up.migrate.deprecated("up.Response#isError()","!up.Response#ok"),!this.ok}}.call(this),function(){up.migrate.renamedProperty(up.radio.config,"hungry","hungrySelectors")}.call(this),function(){var r=[].slice;up.migrate.renamedPackage("layout","viewport"),up.migrate.renamedProperty(up.viewport.config,"viewports","viewportSelectors"),up.migrate.renamedProperty(up.viewport.config,"snap","revealSnap"),up.viewport.closest=function(){var e,t;return e=1<=arguments.length?r.call(arguments,0):[],up.migrate.deprecated("up.viewport.closest()","up.viewport.get()"),(t=up.viewport).get.apply(t,e)}}.call(this),function(){up.framework.stopExtension()}.call(this),function(){}.call(this);
data/dist/unpoly.js CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  (function() {
7
7
  window.up = {
8
- version: "2.0.0-rc8"
8
+ version: "2.0.1"
9
9
  };
10
10
 
11
11
  }).call(this);
@@ -110,20 +110,21 @@ to not include another library in your asset bundle.
110
110
  };
111
111
 
112
112
  /***
113
- Normalizes relative paths and absolute paths to a full URL
114
- that can be checked for equality with other normalized URLs.
115
-
116
- By default hashes are ignored, search queries are included.
113
+ Normalizes the given URL or path.
117
114
 
118
115
  @function up.util.normalizeURL
119
116
  @param {boolean} [options.host='cross-domain']
120
117
  Whether to include protocol, hostname and port in the normalized URL.
118
+
119
+ By default the host is only included if it differ's from the page's hostname.
121
120
  @param {boolean} [options.hash=false]
122
121
  Whether to include an `#hash` anchor in the normalized URL
123
122
  @param {boolean} [options.search=true]
124
123
  Whether to include a `?query` string in the normalized URL
125
124
  @param {boolean} [options.stripTrailingSlash=false]
126
125
  Whether to strip a trailing slash from the pathname
126
+ @return {string}
127
+ The normalized URL.
127
128
  @internal
128
129
  */
129
130
  normalizeURL = function(urlOrAnchor, options) {
@@ -178,6 +179,15 @@ to not include another library in your asset bundle.
178
179
  If the given URL is not fully qualified, it is assumed to be relative
179
180
  to the current page.
180
181
 
182
+ \#\#\# Example
183
+
184
+ ```js
185
+ let parsed = up.util.parseURL('/path?foo=value')
186
+ parsed.pathname // => '/path'
187
+ parsed.search // => '/?foo=value'
188
+ parsed.hash // => ''
189
+ ```
190
+
181
191
  @function up.util.parseURL
182
192
  @return {Object}
183
193
  The parsed URL as an object with
@@ -732,7 +742,7 @@ to not include another library in your asset bundle.
732
742
  @function up.util.isList
733
743
  @param value
734
744
  @return {boolean}
735
- @experimental
745
+ @stable
736
746
  */
737
747
  isList = function(value) {
738
748
  return isArray(value) || isNodeList(value) || isArguments(value) || isJQuery(value) || isHTMLCollection(value);
@@ -775,9 +785,20 @@ to not include another library in your asset bundle.
775
785
  };
776
786
 
777
787
  /***
788
+ Returns the given value if it is [array-like](/up.util.isList), otherwise
789
+ returns an array with the given value as its only element.
790
+
791
+ \#\#\# Example
792
+
793
+ ```js
794
+ up.util.wrapList([1, 2, 3]) // => [1, 2, 3]
795
+ up.util.wrapList('foo') // => ['foo']
796
+ ```
797
+
778
798
  @function up.util.wrapList
799
+ @param {any} value
779
800
  @return {Array|NodeList|jQuery}
780
- @internal
801
+ @experimental
781
802
  */
782
803
  wrapList = function(value) {
783
804
  if (isList(value)) {
@@ -1238,6 +1259,7 @@ to not include another library in your asset bundle.
1238
1259
  @function up.util.last
1239
1260
  @param {Array<T>} array
1240
1261
  @return {T}
1262
+ @stable
1241
1263
  */
1242
1264
  last = function(array) {
1243
1265
  return array[array.length - 1];
@@ -1281,6 +1303,7 @@ to not include another library in your asset bundle.
1281
1303
  @function up.util.pick
1282
1304
  @param {Object} object
1283
1305
  @param {Array} keys
1306
+ @return {Object}
1284
1307
  @stable
1285
1308
  */
1286
1309
  pick = function(object, keys) {
@@ -1294,6 +1317,20 @@ to not include another library in your asset bundle.
1294
1317
  }
1295
1318
  return filtered;
1296
1319
  };
1320
+
1321
+ /***
1322
+ Returns a copy of the given object that only contains
1323
+ properties that pass the given tester function.
1324
+
1325
+ @function up.util.pickBy
1326
+ @param {Object} object
1327
+ @param {Function<string, string, object>} tester
1328
+ A function that will be called with each property.
1329
+
1330
+ The arguments are the property value, key and the entire object.
1331
+ @return {Object}
1332
+ @experimental
1333
+ */
1297
1334
  pickBy = function(object, tester) {
1298
1335
  var filtered, key, value;
1299
1336
  tester = iteratee(tester);
@@ -1359,8 +1396,20 @@ to not include another library in your asset bundle.
1359
1396
  If the given `value` is a function, calls the function with the given `args`.
1360
1397
  Otherwise it just returns `value`.
1361
1398
 
1399
+ \#\#\# Example
1400
+
1401
+ ```js
1402
+ up.util.evalOption(5) // => 5
1403
+
1404
+ let fn = () => 1 + 2
1405
+ up.util.evalOption(fn) // => 3
1406
+ ```
1407
+
1362
1408
  @function up.util.evalOption
1363
- @internal
1409
+ @param {any} value
1410
+ @param {Array} ...args
1411
+ @return {any}
1412
+ @experimental
1364
1413
  */
1365
1414
  evalOption = function() {
1366
1415
  var args, value;
@@ -1384,7 +1433,7 @@ to not include another library in your asset bundle.
1384
1433
 
1385
1434
  @function up.util.escapeHTML
1386
1435
  @param {string} string
1387
- The text that should be escaped
1436
+ The text that should be escaped.
1388
1437
  @stable
1389
1438
  */
1390
1439
  escapeHTML = function(string) {
@@ -1400,6 +1449,17 @@ to not include another library in your asset bundle.
1400
1449
  escapeRegExp = function(string) {
1401
1450
  return string.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
1402
1451
  };
1452
+
1453
+ /***
1454
+ Deletes the property with the given key from the given object
1455
+ and returns its value.
1456
+
1457
+ @function up.util.pluckKey
1458
+ @param {Object} object
1459
+ @param {string} key
1460
+ @return {any}
1461
+ @experimental
1462
+ */
1403
1463
  pluckKey = function(object, key) {
1404
1464
  var value;
1405
1465
  value = object[key];
@@ -1431,7 +1491,6 @@ to not include another library in your asset bundle.
1431
1491
  @param {Array<Function()>} functions
1432
1492
  @return {Function()}
1433
1493
  A function that will call all `functions` if called.
1434
-
1435
1494
  @internal
1436
1495
  */
1437
1496
  sequence = function(functions) {
@@ -1447,7 +1506,13 @@ to not include another library in your asset bundle.
1447
1506
  };
1448
1507
 
1449
1508
  /***
1450
- Flattens the given `array` a single level deep.
1509
+ Flattens the given `array` a single depth level.
1510
+
1511
+ \#\#\# Example
1512
+
1513
+ ```js
1514
+ let nested = [1, [2, 3], [4]]
1515
+ up.util.flatten(nested) // => [1, 2, 3, 4]
1451
1516
 
1452
1517
  @function up.util.flatten
1453
1518
  @param {Array} array
@@ -1472,7 +1537,7 @@ to not include another library in your asset bundle.
1472
1537
 
1473
1538
  /***
1474
1539
  Maps each element using a mapping function,
1475
- then flattens the result into a new array.
1540
+ then [flattens](/up.util.flatten) the result into a new array.
1476
1541
 
1477
1542
  @function up.util.flatMap
1478
1543
  @param {Array} array
@@ -1508,24 +1573,24 @@ to not include another library in your asset bundle.
1508
1573
  };
1509
1574
 
1510
1575
  /***
1511
- * Registers an empty rejection handler with the given promise.
1512
- * This prevents browsers from printing "Uncaught (in promise)" to the error
1513
- * console when the promise is rejected.
1514
- *
1515
- * This is helpful for event handlers where it is clear that no rejection
1516
- * handler will be registered:
1517
- *
1518
- * up.on('submit', 'form[up-target]', (event, $form) => {
1519
- * promise = up.submit($form)
1520
- * up.util.muteRejection(promise)
1521
- * })
1522
- *
1523
- * Does nothing if passed a missing value.
1524
- *
1525
- * @function up.util.muteRejection
1526
- * @param {Promise|undefined|null} promise
1527
- * @return {Promise}
1528
- * @internal
1576
+ Registers an empty rejection handler with the given promise.
1577
+ This prevents browsers from printing "Uncaught (in promise)" to the error
1578
+ console when the promise is rejected.
1579
+
1580
+ This is helpful for event handlers where it is clear that no rejection
1581
+ handler will be registered:
1582
+
1583
+ up.on('submit', 'form[up-target]', (event, $form) => {
1584
+ promise = up.submit($form)
1585
+ up.util.muteRejection(promise)
1586
+ })
1587
+
1588
+ Does nothing if passed a missing value.
1589
+
1590
+ @function up.util.muteRejection
1591
+ @param {Promise|undefined|null} promise
1592
+ @return {Promise}
1593
+ @internal
1529
1594
  */
1530
1595
  muteRejection = function(promise) {
1531
1596
  return promise != null ? promise["catch"](noop) : void 0;
@@ -2081,10 +2146,12 @@ Chrome, Firefox, Edge, Safari
2081
2146
  : Full support
2082
2147
 
2083
2148
  Internet Explorer 11
2084
- : Full support with a `Promise` polyfill like [es6-promise](https://github.com/stefanpenner/es6-promise) (2.4 KB).
2149
+ : Full support with a `Promise` polyfill like [es6-promise](https://github.com/stefanpenner/es6-promise) (2.4 KB).\
2150
+ Support may be removed when Microsoft retires IE11 in [June 2022](https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/).
2085
2151
 
2086
2152
  Internet Explorer 10 or lower
2087
- : Unpoly prevents itself from booting itself, leaving you with a classic server-side application.
2153
+ : Unpoly will not boot or [run compilers](/up.compiler),
2154
+ leaving you with a classic server-side application.
2088
2155
 
2089
2156
  @module up.browser
2090
2157
  */
@@ -2097,7 +2164,9 @@ Internet Explorer 10 or lower
2097
2164
  u = up.util;
2098
2165
 
2099
2166
  /***
2100
- Makes a full page request, replacing the entire JavaScript environment with a new page from the server response.
2167
+ Makes a full-page request, replacing the entire browser environment with a new page from the server response.
2168
+
2169
+ Also see `up.Request#loadPage()`.
2101
2170
 
2102
2171
  @function up.browser.loadPage
2103
2172
  @param {string} options.url
@@ -2107,7 +2176,7 @@ Internet Explorer 10 or lower
2107
2176
 
2108
2177
  Methods other than GET or POST will be [wrapped](/up.protocol.config#config.methodParam) in a POST request.
2109
2178
  @param {Object|Array|FormData|string} [options.params]
2110
- @external
2179
+ @experimental
2111
2180
  */
2112
2181
  loadPage = function(requestsAttrs) {
2113
2182
  return new up.Request(requestsAttrs).loadPage();
@@ -2239,7 +2308,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
2239
2308
  var slice = [].slice;
2240
2309
 
2241
2310
  up.element = (function() {
2242
- var CSS_LENGTH_PROPS, MATCH_FN_NAME, SINGLETON_PATTERN, SINGLETON_TAG_NAMES, affix, all, ancestor, around, attributeSelector, booleanAttr, booleanOrStringAttr, callbackAttr, closest, closestAttr, computedStyle, computedStyleNumber, concludeCSSTransition, createDocumentFromHTML, createFromHTML, createFromSelector, cssLength, elementTagName, extractFromStyleObject, first, fixedToAbsolute, getList, getOne, getRoot, hasCSSTransition, hide, idSelector, inlineStyle, insertBefore, isDetached, isInSubtree, isSingleton, isSingletonSelector, isVisible, jsonAttr, matches, metaContent, normalizeStyleValueForWrite, numberAttr, paint, remove, replace, setAttrs, setInlineStyle, setMissingAttr, setMissingAttrs, setTemporaryAttrs, setTemporaryStyle, show, stringAttr, subtree, toSelector, toggle, toggleAttr, toggleClass, trueAttributeSelector, u, unwrap, upAttrs, valueToList, wrapChildren;
2311
+ var CSS_LENGTH_PROPS, MATCH_FN_NAME, SINGLETON_PATTERN, SINGLETON_TAG_NAMES, affix, all, ancestor, around, attributeSelector, booleanAttr, booleanOrStringAttr, callbackAttr, classSelector, closest, closestAttr, computedStyle, computedStyleNumber, concludeCSSTransition, createDocumentFromHTML, createFromHTML, createFromSelector, cssLength, elementTagName, extractFromStyleObject, first, fixedToAbsolute, getList, getOne, getRoot, hasCSSTransition, hide, idSelector, inlineStyle, insertBefore, isDetached, isInSubtree, isSingleton, isSingletonSelector, isVisible, jsonAttr, matches, metaContent, normalizeStyleValueForWrite, numberAttr, paint, remove, replace, setAttrs, setInlineStyle, setMissingAttr, setMissingAttrs, setTemporaryAttrs, setTemporaryStyle, show, stringAttr, subtree, toSelector, toggle, toggleAttr, toggleClass, trueAttributeSelector, u, unwrap, upAttrs, valueToList, wrapChildren;
2243
2312
  u = up.util;
2244
2313
  MATCH_FN_NAME = up.browser.isIE11() ? 'msMatchesSelector' : 'matches';
2245
2314
 
@@ -2521,12 +2590,8 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
2521
2590
  [this WHATWG mailing list post](http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Apr/0094.html).
2522
2591
 
2523
2592
  @function up.element.show
2524
- <<<<<<< HEAD:lib/assets/javascripts/unpoly/element.coffee
2525
- @stable
2526
- =======
2527
2593
  @param {Element} element
2528
- @experimental
2529
- >>>>>>> 0d20e224... Adjust docs:lib/assets/javascripts/unpoly/element.coffee.erb
2594
+ @stable
2530
2595
  */
2531
2596
  show = function(element) {
2532
2597
  return element.style.display = '';
@@ -2563,7 +2628,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
2563
2628
  @function up.element.toggleClass
2564
2629
  @param {Element} element
2565
2630
  The element for which to add or remove the class.
2566
- @param {String} className
2631
+ @param {string} className
2567
2632
  The class which should be added or removed.
2568
2633
  @param {Boolean} [newPresent]
2569
2634
  Pass `true` to add the class to the element or `false` to remove it.
@@ -2916,6 +2981,15 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
2916
2981
  }
2917
2982
  };
2918
2983
 
2984
+ /***
2985
+ @function up.element.classSelector
2986
+ @internal
2987
+ */
2988
+ classSelector = function(klass) {
2989
+ klass = klass.replace(/:/g, '\\:');
2990
+ return "." + klass;
2991
+ };
2992
+
2919
2993
  /***
2920
2994
  Always creates a full document with a <html> root, even if the given `html`
2921
2995
  is only a fragment.
@@ -3449,6 +3523,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
3449
3523
  affix: affix,
3450
3524
  toSelector: toSelector,
3451
3525
  idSelector: idSelector,
3526
+ classSelector: classSelector,
3452
3527
  isSingleton: isSingleton,
3453
3528
  isSingletonSelector: isSingletonSelector,
3454
3529
  attributeSelector: attributeSelector,
@@ -4993,7 +5068,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
4993
5068
  };
4994
5069
 
4995
5070
  CompilerPass.prototype.runCompiler = function(compiler) {
4996
- var i, j, keepValue, len, len1, match, matches, results, value;
5071
+ var base, i, len, match, matches;
4997
5072
  matches = this.select(compiler.selector);
4998
5073
  if (!matches.length) {
4999
5074
  return;
@@ -5009,15 +5084,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
5009
5084
  this.compileOneElement(compiler, match);
5010
5085
  }
5011
5086
  }
5012
- if (keepValue = compiler.keep) {
5013
- value = u.isString(keepValue) ? keepValue : '';
5014
- results = [];
5015
- for (j = 0, len1 = matches.length; j < len1; j++) {
5016
- match = matches[j];
5017
- results.push(match.setAttribute('up-keep', value));
5018
- }
5019
- return results;
5020
- }
5087
+ return typeof (base = up.migrate).postCompile === "function" ? base.postCompile(matches, compiler) : void 0;
5021
5088
  };
5022
5089
 
5023
5090
  CompilerPass.prototype.compileOneElement = function(compiler, element) {
@@ -6238,8 +6305,12 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6238
6305
  /***
6239
6306
  Each layer has an `up.Layer` instance.
6240
6307
 
6241
- Most functions in the `up.layer` (lowercase) package interact with the [current layer](/up.layer.current).
6242
- E.g. `up.layer.dismiss()` is a shortcut for `up.layer.current.dismiss()`.
6308
+ Most functions in the `up.layer` package interact with the [current layer](/up.layer.current).
6309
+ For example, `up.layer.dismiss()` is a shortcut for `up.layer.current.dismiss()`.
6310
+
6311
+ `up.layer.current` is set to the right layer in compilers and most events,
6312
+ even if that layer is not the frontmost layer. E.g. if you're compiling a fragment for a background layer, `up.layer.current` will be
6313
+ the background layer during compilation.
6243
6314
 
6244
6315
  @class up.Layer
6245
6316
  */
@@ -6266,66 +6337,46 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6266
6337
 
6267
6338
 
6268
6339
  /***
6269
- This layer's mode which governs its appearance and behavior.
6270
-
6271
- Available layer modes are:
6340
+ Whether fragment updates within this layer can affect browser history and window title.
6272
6341
 
6273
- - `'root'`
6274
- - `'modal'`
6275
- - `'popup'`
6276
- - `'drawer'`
6277
- - `'cover'`
6342
+ If a layer does not have visible history, its desendant layers cannot have history either.
6278
6343
 
6279
- @property up.Layer#mode
6280
- @param {string} mode
6344
+ @property up.Layer#historyVisible
6345
+ @param {boolean} historyVisible
6281
6346
  @stable
6282
6347
  */
6283
6348
 
6284
6349
 
6285
6350
  /***
6286
- Whether fragment updates within this layer can affect browser history and window title.
6351
+ This layer's mode which governs its appearance and behavior.
6287
6352
 
6288
- @property up.Layer#historyVisible
6289
- @param {boolean} historyVisible
6353
+ @see layer-terminology
6354
+
6355
+ @property up.Layer#mode
6356
+ @param {string} mode
6357
+ @stable
6290
6358
  */
6291
6359
 
6292
6360
 
6293
6361
  /***
6294
- This layer's context object.
6295
-
6296
- Think of *context* as [session storage](/https://makandracards.com/makandra/32865), but specific to a [layer](/up.layer)
6297
- rather than specific to an entire browser tab.
6298
-
6299
- You may access the context object's properties like a regular JavaScript object.
6362
+ This layer's [context](/context).
6300
6363
 
6301
6364
  \#\#\# Example
6302
6365
 
6366
+ You may access the context properties like a regular JavaScript object.
6367
+
6303
6368
  ```js
6304
6369
  let layer = up.layer.current
6305
6370
  layer.context.message = 'Please select a contact'
6306
6371
  console.log(layer.context) // logs "{ message: 'Please select a contact' }"
6307
6372
  ```
6308
6373
 
6309
- \#\#\# Accessing the context from the server
6310
-
6311
- The context is is sent as an `X-Up-Context` header along with every
6312
- [request](/up.request) to the server. The server may also update the updating
6313
- layer's context by including an `X-Up-Context` header in its response.
6314
-
6315
6374
  @property up.Layer#context
6316
6375
  @param {Object} context
6317
- @stable
6318
- */
6319
-
6320
-
6321
- /***
6322
- Whether fragment updates within this layer will affect [browser history](/up.history).
6323
-
6324
- If a layer does not have visible history, its desendant layers cannot have history either.
6376
+ The context object.
6325
6377
 
6326
- @property up.Layer#historyVisible
6327
- @param {boolean} historyVisible
6328
- @stable
6378
+ If no context has been set an empty object is returned.
6379
+ @experimental
6329
6380
  */
6330
6381
 
6331
6382
  Layer.prototype.keys = function() {
@@ -6384,7 +6435,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6384
6435
  [Closes this overlay](/closing-overlays) with an accepting intent,
6385
6436
  e.g. when a change was confirmed or when a value was selected.
6386
6437
 
6387
- To dismiss a layer without an accepting intent, use `up.Layer#dismiss()` instead.
6438
+ To dismiss a layer *without* an accepting intent, use `up.Layer#dismiss()` instead.
6388
6439
 
6389
6440
  @function up.Layer#accept
6390
6441
  @param {any} [value]
@@ -6422,7 +6473,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6422
6473
 
6423
6474
 
6424
6475
  /***
6425
- [Closes this overlay](/closing-overlays) without an accepting intent,
6476
+ [Closes this overlay](/closing-overlays) *without* an accepting intent,
6426
6477
  e.g. when a "Cancel" button was clicked.
6427
6478
 
6428
6479
  To close an overlay with an accepting intent, use `up.Layer#accept()` instead.
@@ -6497,7 +6548,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6497
6548
  /***
6498
6549
  Returns whether this layer is the [root layer](/up.layer.root).
6499
6550
 
6500
- @function up.Layer#isFront
6551
+ @function up.Layer#isRoot
6501
6552
  @return {boolean}
6502
6553
  @stable
6503
6554
  */
@@ -6578,7 +6629,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6578
6629
 
6579
6630
  Returns `undefined` if this layer has not opened a child layer.
6580
6631
 
6581
- A layer can have at most one child layer. Opening an overlay on a layer with an exiisting child will
6632
+ A layer can have at most one child layer. Opening an overlay on a layer with an existing child will
6582
6633
  first dismiss the existing child before replacing it with the new child.
6583
6634
 
6584
6635
  @property up.Layer#child
@@ -6594,6 +6645,10 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6594
6645
  /***
6595
6646
  Returns an array of this layer's ancestor layers.
6596
6647
 
6648
+ The array elements are ordered by distance to this layer.
6649
+ The first element is this layer's direct parent. The last element
6650
+ is the [root layer](/up.layer.root).
6651
+
6597
6652
  @property up.Layer#ancestors
6598
6653
  @return {Array<up.Layer>} ancestors
6599
6654
  @stable
@@ -6609,6 +6664,10 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6609
6664
 
6610
6665
  Descendant layers are all layers that visually overlay this layer.
6611
6666
 
6667
+ The array elements are ordered by distance to this layer.
6668
+ The first element is this layer's direct child. The last element
6669
+ is the [frontmost layer](/up.layer.front).
6670
+
6612
6671
  @property up.Layer#descendants
6613
6672
  @return {Array<up.Layer>} descendants
6614
6673
  @stable
@@ -6668,7 +6727,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6668
6727
 
6669
6728
 
6670
6729
  /***
6671
- Listens to a ([DOM event](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events) that originated
6730
+ Listens to a [DOM event](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events) that originated
6672
6731
  on an element [contained](/up.Layer.prototype.contains) by this layer.
6673
6732
 
6674
6733
  This will ignore events emitted on elements in [descendant](/up.Layer.prototype.descendants) overlays,
@@ -6705,27 +6764,43 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6705
6764
  up.follow(overlayLink) // listener is not called
6706
6765
 
6707
6766
  @function up.Layer#on
6767
+
6708
6768
  @param {string} types
6709
6769
  A space-separated list of event types to bind to.
6710
- @param {string} [selector]
6770
+
6771
+ @param {string|Function(): string} [selector]
6711
6772
  The selector of an element on which the event must be triggered.
6712
6773
 
6713
6774
  Omit the selector to listen to all events of the given type, regardless
6714
6775
  of the event target.
6776
+
6777
+ If the selector is not known in advance you may also pass a function
6778
+ that returns the selector. The function is evaluated every time
6779
+ an event with the given type is observed.
6780
+
6715
6781
  @param {boolean} [options.passive=false]
6716
6782
  Whether to register a [passive event listener](https://developers.google.com/web/updates/2016/06/passive-event-listeners).
6717
6783
 
6718
6784
  A passive event listener may not call `event.preventDefault()`.
6719
6785
  This in particular may improve the frame rate when registering
6720
6786
  `touchstart` and `touchmove` events.
6787
+
6788
+ @param {boolean} [options.once=true]
6789
+ Whether the listener should run at most once.
6790
+
6791
+ If `true` the listener will automatically be unbound
6792
+ after the first invocation.
6793
+
6721
6794
  @param {Function(event, [element], [data])} listener
6722
6795
  The listener function that should be called.
6723
6796
 
6724
6797
  The function takes the affected element as the second argument.
6725
6798
  If the element has an [`up-data`](/up-data) attribute, its value is parsed as JSON
6726
6799
  and passed as a third argument.
6800
+
6727
6801
  @return {Function()}
6728
6802
  A function that unbinds the event listeners when called.
6803
+
6729
6804
  @stable
6730
6805
  */
6731
6806
 
@@ -6740,13 +6815,12 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6740
6815
  Unbinds an event listener previously bound with `up.Layer#on()`.
6741
6816
 
6742
6817
  @function up.Layer#off
6743
- @param {Element|jQuery} [element=document]
6744
6818
  @param {string} events
6745
- @param {string} [selector]
6819
+ @param {string|Function(): string} [selector]
6746
6820
  @param {Function(event, [element], [data])} listener
6747
6821
  The listener function to unbind.
6748
6822
 
6749
- Note that you must pass a reference to the exact same listener function
6823
+ Note that you must pass a reference to the same function reference
6750
6824
  that was passed to `up.Layer#on()` earlier.
6751
6825
  @stable
6752
6826
  */
@@ -6918,9 +6992,9 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6918
6992
  /***
6919
6993
  This layer's location URL.
6920
6994
 
6921
- If the [frontmost layer](/up.layer.front) does not have [visible history](/up.Layer.prototype.historyVisible),
6995
+ If the layer has [no visible history](/up.Layer.prototype.historyVisible), this property
6996
+ still returns the URL of the content in the overlay. In this case
6922
6997
  the browser's address bar will show the location of an ancestor layer.
6923
- This property will return the URL the layer would use if it had visible history.
6924
6998
 
6925
6999
  When this layer opens a child layer with visible history, the browser URL will change to the child
6926
7000
  layer's location. When the child layer is closed, this layer's location will be restored.
@@ -7243,7 +7317,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
7243
7317
  If the destruction is animated, the callback will run after the animation has finished.
7244
7318
  @return {Promise}
7245
7319
  A resolved promise.
7246
- @private
7320
+ @internal
7247
7321
  */
7248
7322
 
7249
7323
  Overlay.prototype.destroyElements = function(options) {
@@ -7382,6 +7456,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
7382
7456
  /***
7383
7457
  @function up.Layer.OverlayWithViewport#openNow
7384
7458
  @param {Element} options.content
7459
+ @internal
7385
7460
  */
7386
7461
 
7387
7462
  OverlayWithViewport.prototype.createElements = function(content) {
@@ -8895,6 +8970,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
8895
8970
  @param {string} name
8896
8971
  @return {any}
8897
8972
  The value of the param with the given name.
8973
+ @internal
8898
8974
  */
8899
8975
 
8900
8976
  Params.prototype.getFirst = function(name) {
@@ -8913,6 +8989,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
8913
8989
  @param {string} name
8914
8990
  @return {Array}
8915
8991
  An array of all values with the given name.
8992
+ @internal
8916
8993
  */
8917
8994
 
8918
8995
  Params.prototype.getAll = function(name) {
@@ -9260,7 +9337,15 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9260
9337
 
9261
9338
 
9262
9339
  /***
9263
- Instances of `up.RenderResult` describe the effects of [rendering](/up.fragment).
9340
+ Instances of `up.RenderResult` describe the effects of [rendering](/up.render).
9341
+
9342
+ It is returned by functions like `up.render()` or `up.navigate()`:
9343
+
9344
+ ```js
9345
+ let result = await up.render('.target', content: 'foo')
9346
+ console.log(result.fragments) // => [<div class="target">...</div>]
9347
+ console.log(result.layer) // => up.Layer.Root
9348
+ ```
9264
9349
 
9265
9350
  @class up.RenderResult
9266
9351
  */
@@ -9311,17 +9396,18 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9311
9396
 
9312
9397
 
9313
9398
  /***
9314
- Instances of `up.Request` normalizes properties of an [`AJAX request`](/up.request)
9315
- such as the requested URL, form parameters and HTTP method.
9399
+ A normalized description of an [HTTP request](`up.request()`).
9316
9400
 
9317
9401
  You can queue a request using the `up.request()` method:
9318
9402
 
9319
- let request = up.request('/foo')
9320
- console.log(request.url)
9403
+ ```js
9404
+ let request = up.request('/foo')
9405
+ console.log(request.url)
9321
9406
 
9322
- // A request object is also a promise for its response
9323
- let response = await request
9324
- console.log(response.text)
9407
+ // A request object is also a promise for its response
9408
+ let response = await request
9409
+ console.log(response.text)
9410
+ ```
9325
9411
 
9326
9412
  @class up.Request
9327
9413
  */
@@ -9348,6 +9434,23 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9348
9434
  */
9349
9435
 
9350
9436
 
9437
+ /***
9438
+ The [hash component](https://en.wikipedia.org/wiki/URI_fragment) of this request's URL.
9439
+
9440
+ The `{ hash }` property is automatically extracted from the given URL:
9441
+
9442
+ ```js
9443
+ let request = up.request({ url: '/path#section' })
9444
+ request.url // => '/path'
9445
+ request.hash // => '#section'
9446
+ ```
9447
+
9448
+ @property up.Request#hash
9449
+ @param {string} hash
9450
+ @stable
9451
+ */
9452
+
9453
+
9351
9454
  /***
9352
9455
  [Parameters](/up.Params) that should be sent as the request's payload.
9353
9456
 
@@ -9358,7 +9461,9 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9358
9461
 
9359
9462
 
9360
9463
  /***
9361
- The CSS selector that will be sent as an `X-Up-Target` header.
9464
+ The CSS selector targeted by this request.
9465
+
9466
+ The selector will be sent as an `X-Up-Target` header.
9362
9467
 
9363
9468
  @property up.Request#target
9364
9469
  @param {string} target
@@ -9367,7 +9472,10 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9367
9472
 
9368
9473
 
9369
9474
  /***
9370
- The CSS selector that will be sent as an `X-Up-Fail-Target` header.
9475
+ The CSS selector targeted by this request in case the server responds
9476
+ with an [error code](/server-errors).
9477
+
9478
+ The selector will be sent as an `X-Up-Fail-Target` header.
9371
9479
 
9372
9480
  @property up.Request#failTarget
9373
9481
  @param {string} failTarget
@@ -9378,7 +9486,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9378
9486
  /***
9379
9487
  An object of additional HTTP headers.
9380
9488
 
9381
- Note that Unpoly will by default send a number of custom request headers.
9489
+ Unpoly will by default send a number of custom request headers.
9382
9490
  See `up.protocol` and `up.network.config.metaKeys` for details.
9383
9491
 
9384
9492
  @property up.Request#headers
@@ -9414,25 +9522,71 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9414
9522
 
9415
9523
 
9416
9524
  /***
9417
- TODO: Docs
9525
+ The [context](/contact) of the layer targeted by this request.
9526
+
9527
+ The context object will be sent as an `X-Up-Context` header.
9418
9528
 
9419
9529
  @property up.Request#context
9420
9530
  @param {Object} context
9421
- @stable
9531
+ @experimental
9422
9532
  */
9423
9533
 
9424
9534
 
9425
9535
  /***
9426
- TODO: Docs
9536
+ The [context](/contact) of the layer targeted by this request in case the server responds with an [error code](/server-errors).
9537
+
9538
+ The context object will be sent as an `X-Up-Fail-Context` header.
9427
9539
 
9428
9540
  @property up.Request#failContext
9429
9541
  @param {Object} failContext
9430
- @stable
9542
+ @experimental
9543
+ */
9544
+
9545
+
9546
+ /***
9547
+ The [layer](/up.layer) targeted by this request.
9548
+
9549
+ Setting the `{ layer }` property will automatically derive `{ context }` and `{ mode }` properties.
9550
+
9551
+ To prevent memory leaks, this property is removed shortly after the response is received.
9552
+
9553
+ @property up.Request#layer
9554
+ @param {up.Layer} layer
9555
+ @experimental
9556
+ */
9557
+
9558
+
9559
+ /***
9560
+ The [layer](/up.layer) targeted by this request in case the server responds with an [error code](/server-errors).
9561
+
9562
+ Setting the `{ failLayer }` property will automatically derive `{ failContext }` and `{ failMode }` properties.
9563
+
9564
+ To prevent memory leaks, this property is removed shortly after the response is received.
9565
+
9566
+ @property up.Request#failLayer
9567
+ @param {up.Layer} layer
9568
+ @experimental
9569
+ */
9570
+
9571
+
9572
+ /***
9573
+ The element that triggered the request.
9574
+
9575
+ For example, when this request was triggered by a click on a link, the lonk
9576
+ element is set as the `{ origin }`.
9577
+
9578
+ To prevent memory leaks, this property is removed shortly after the response is received.
9579
+
9580
+ @property up.Request#origin
9581
+ @param {Element} origin
9582
+ @experimental
9431
9583
  */
9432
9584
 
9433
9585
 
9434
9586
  /***
9435
- TODO: Docs
9587
+ The [mode](/up.Layer.prototype.mode) of the layer targeted by this request.
9588
+
9589
+ The value will be sent as an `X-Up-Mode` header.
9436
9590
 
9437
9591
  @property up.Request#mode
9438
9592
  @param {string} mode
@@ -9441,7 +9595,9 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9441
9595
 
9442
9596
 
9443
9597
  /***
9444
- TODO: Docs
9598
+ The [mode](/up.Layer.prototype.mode) of the layer targeted by this request in case the server responds with an [error code](/server-errors).
9599
+
9600
+ The value will be sent as an `X-Up-Fail-Mode` header.
9445
9601
 
9446
9602
  @property up.Request#failMode
9447
9603
  @param {string} failMode
@@ -9450,7 +9606,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9450
9606
 
9451
9607
 
9452
9608
  /***
9453
- TODO: Docs
9609
+ The format in which the [request params](/up.Layer.prototype.params) will be encoded.
9454
9610
 
9455
9611
  @property up.Request#contentType
9456
9612
  @param {string} contentType
@@ -9459,13 +9615,22 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9459
9615
 
9460
9616
 
9461
9617
  /***
9462
- TODO: Docs
9618
+ The payload that the request will encode into its body.
9619
+
9620
+ By default Unpoly will build a payload from the given `{ params }` option.
9463
9621
 
9464
9622
  @property up.Request#payload
9465
9623
  @param {string} payload
9466
9624
  @stable
9467
9625
  */
9468
9626
 
9627
+
9628
+ /***
9629
+ @property up.Request#preload
9630
+ @param {boolean} preload
9631
+ @experimental
9632
+ */
9633
+
9469
9634
  Request.prototype.keys = function() {
9470
9635
  return ['method', 'url', 'hash', 'params', 'target', 'failTarget', 'headers', 'timeout', 'preload', 'cache', 'clearCache', 'layer', 'mode', 'context', 'failLayer', 'failMode', 'failContext', 'origin', 'solo', 'queueTime', 'wrapMethod', 'contentType', 'payload', 'onQueued'];
9471
9636
  };
@@ -9521,7 +9686,8 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9521
9686
  Request.prototype.normalizeForCaching = function() {
9522
9687
  this.method = u.normalizeMethod(this.method);
9523
9688
  this.extractHashFromURL();
9524
- return this.transferParamsToURL();
9689
+ this.transferParamsToURL();
9690
+ return this.url = u.normalizeURL(this.url);
9525
9691
  };
9526
9692
 
9527
9693
  Request.prototype.evictExpensiveAttrs = function() {
@@ -9608,6 +9774,37 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9608
9774
  });
9609
9775
  };
9610
9776
 
9777
+
9778
+ /***
9779
+ Loads this request object as a full-page request, replacing the entire browser environment
9780
+ with a new page from the server response.
9781
+
9782
+ The full-page request will be loaded with the [URL](/up.Request.prototype.url),
9783
+ [method](/up.Request.prototype.method) and [params](/up.Request.prototype.params)
9784
+ from this request object.
9785
+ Properties that are not possible in a full-page request (such as custom HTTP headers)
9786
+ will be ignored.
9787
+
9788
+ \#\#\# Example
9789
+
9790
+ ```javascript
9791
+ let request = await up.request('/path')
9792
+
9793
+ try {
9794
+ let response = await request('/path')
9795
+ } catch (result) {
9796
+ if (result.name === 'AbortError') {
9797
+ console.log('Request was aborted.')
9798
+ }
9799
+ }
9800
+
9801
+ request.abort()
9802
+ ```
9803
+
9804
+ @function up.Request#loadPage
9805
+ @experimental
9806
+ */
9807
+
9611
9808
  Request.prototype.loadPage = function() {
9612
9809
  up.network.abort();
9613
9810
  return new up.Request.FormRenderer(this).buildAndSubmit();
@@ -10187,7 +10384,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10187
10384
 
10188
10385
 
10189
10386
  /***
10190
- Instances of `up.Response` describe the server response to an [`AJAX request`](/up.request).
10387
+ A response to an [HTTP request](`up.request()`).
10191
10388
 
10192
10389
  \#\#\# Example
10193
10390
 
@@ -10299,6 +10496,14 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10299
10496
  @experimental
10300
10497
  */
10301
10498
 
10499
+
10500
+ /***
10501
+ Changes to the current [context](/context) as [set by the server](/X-Up-Context).
10502
+
10503
+ @property up.Response#context
10504
+ @experimental
10505
+ */
10506
+
10302
10507
  Response.prototype.keys = function() {
10303
10508
  return ['method', 'url', 'text', 'status', 'request', 'xhr', 'target', 'title', 'acceptLayer', 'dismissLayer', 'eventPlans', 'context', 'clearCache', 'headers'];
10304
10509
  };
@@ -10845,7 +11050,8 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10845
11050
 
10846
11051
  }).call(this);
10847
11052
  (function() {
10848
- var e, u;
11053
+ var e, u,
11054
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
10849
11055
 
10850
11056
  u = up.util;
10851
11057
 
@@ -10853,6 +11059,8 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10853
11059
 
10854
11060
  up.Tether = (function() {
10855
11061
  function Tether(options) {
11062
+ this.sync = bind(this.sync, this);
11063
+ this.scheduleSync = bind(this.scheduleSync, this);
10856
11064
  var base;
10857
11065
  if (typeof (base = up.migrate).handleTetherOptions === "function") {
10858
11066
  base.handleTetherOptions(options);
@@ -10895,8 +11103,14 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10895
11103
  };
10896
11104
 
10897
11105
  Tether.prototype.sync = function() {
10898
- var anchorBox, elementBox, left, top;
11106
+ var anchorBox, elementBox, elementMargin, left, top;
10899
11107
  elementBox = this.element.getBoundingClientRect();
11108
+ elementMargin = {
11109
+ top: e.styleNumber(this.element, 'marginTop'),
11110
+ right: e.styleNumber(this.element, 'marginRight'),
11111
+ bottom: e.styleNumber(this.element, 'marginBottom'),
11112
+ left: e.styleNumber(this.element, 'marginLeft')
11113
+ };
10900
11114
  anchorBox = this.anchor.getBoundingClientRect();
10901
11115
  left = void 0;
10902
11116
  top = void 0;
@@ -10905,19 +11119,19 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10905
11119
  top = (function() {
10906
11120
  switch (this.position) {
10907
11121
  case 'top':
10908
- return anchorBox.top - elementBox.height;
11122
+ return anchorBox.top - elementMargin.bottom - elementBox.height;
10909
11123
  case 'bottom':
10910
- return anchorBox.top + anchorBox.height;
11124
+ return anchorBox.top + anchorBox.height + elementMargin.top;
10911
11125
  }
10912
11126
  }).call(this);
10913
11127
  left = (function() {
10914
11128
  switch (this.align) {
10915
11129
  case 'left':
10916
- return anchorBox.left;
11130
+ return anchorBox.left + elementMargin.left;
10917
11131
  case 'center':
10918
11132
  return anchorBox.left + 0.5 * (anchorBox.width - elementBox.width);
10919
11133
  case 'right':
10920
- return anchorBox.left + anchorBox.width - elementBox.width;
11134
+ return anchorBox.left + anchorBox.width - elementBox.width - elementMargin.right;
10921
11135
  }
10922
11136
  }).call(this);
10923
11137
  break;
@@ -10925,19 +11139,19 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10925
11139
  top = (function() {
10926
11140
  switch (this.align) {
10927
11141
  case 'top':
10928
- return anchorBox.top;
11142
+ return anchorBox.top + elementMargin.top;
10929
11143
  case 'center':
10930
11144
  return anchorBox.top + 0.5 * (anchorBox.height - elementBox.height);
10931
11145
  case 'bottom':
10932
- return anchorBox.top + anchorBox.height - elementBox.height;
11146
+ return anchorBox.top + anchorBox.height - elementBox.height - elementMargin.bottom;
10933
11147
  }
10934
11148
  }).call(this);
10935
11149
  left = (function() {
10936
11150
  switch (this.position) {
10937
11151
  case 'left':
10938
- return anchorBox.left - elementBox.width;
11152
+ return anchorBox.left - elementMargin.right - elementBox.width;
10939
11153
  case 'right':
10940
- return anchorBox.left + anchorBox.width;
11154
+ return anchorBox.left + anchorBox.width + elementMargin.left;
10941
11155
  }
10942
11156
  }).call(this);
10943
11157
  }
@@ -11154,37 +11368,26 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
11154
11368
  Events
11155
11369
  ======
11156
11370
 
11157
- This module contains functions to [build](/up.event.build), [dispatch](/up.emit) and [listen to](/up.on) DOM events.
11371
+ This module contains functions to [emit](/up.emit) and [observe](/up.on) DOM events.
11158
11372
 
11159
- While the browser also ships with functions like [`Element#dispatchEvent()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent)
11160
- and [`Element#addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to
11161
- work with DOM events, you will find the functions in this module to be more convenient and feature-rich.
11373
+ While the browser also has built-in functions to work with events,
11374
+ you will find Unpoly's functions to be very concise and feature-rich.
11162
11375
 
11163
11376
  ## Events emitted by Unpoly
11164
11377
 
11165
- Most Unpoly interactions emit DOM events that are prefixed with `up:`.
11166
-
11167
- ```javascript
11168
- document.addEventListener('up:modal:opened', (event) => {
11169
- console.log('A new modal has just opened!')
11170
- })
11171
- ```
11172
-
11173
- Events often have both present and past forms. For example, `up:layer:open` is emitted before an overlay starts to open.
11174
- `up:layer:opened` is emitted when the overlay has appeared in the DOM tree.
11378
+ Most Unpoly features emit events that are prefixed with `up:`.
11175
11379
 
11176
- \#\#\# Preventing events
11380
+ Unpoly's own events are documented in their respective modules, for example:
11177
11381
 
11178
- You can prevent most present form events by calling `preventDefault()`:
11382
+ | Event | Module |
11383
+ |-----------------------|--------------------|
11384
+ | `up:link:follow` | `up.link` |
11385
+ | `up:form:submit` | `up.form` |
11386
+ | `up:layer:open` | `up.layer` |
11387
+ | `up:request:late` | `up.network` |
11179
11388
 
11180
- ```javascript
11181
- document.addEventListener('up:modal:open', (event) => {
11182
- if (event.url == '/evil') {
11183
- // Prevent the modal from opening
11184
- event.preventDefault()
11185
- }
11186
- })
11187
- ```
11389
+ @see up.on
11390
+ @see up.emit
11188
11391
 
11189
11392
  @module up.event
11190
11393
  */
@@ -11324,12 +11527,16 @@ document.addEventListener('up:modal:open', (event) => {
11324
11527
  Multiple event types may be passed as either a space-separated string
11325
11528
  or as an array of types.
11326
11529
 
11327
- @param {string} [selector]
11530
+ @param {string|Function():string} [selector]
11328
11531
  The selector of an element on which the event must be triggered.
11329
11532
 
11330
11533
  Omit the selector to listen to all events of the given type, regardless
11331
11534
  of the event target.
11332
11535
 
11536
+ If the selector is not known in advance you may also pass a function
11537
+ that returns the selector. The function is evaluated every time
11538
+ an event with the given type is observed.
11539
+
11333
11540
  @param {boolean} [options.passive=false]
11334
11541
  Whether to register a [passive event listener](https://developers.google.com/web/updates/2016/06/passive-event-listeners).
11335
11542
 
@@ -11340,7 +11547,7 @@ document.addEventListener('up:modal:open', (event) => {
11340
11547
  @param {boolean} [options.once=true]
11341
11548
  Whether the listener should run at most once.
11342
11549
 
11343
- If `true` the listener will automatically be removed from the element
11550
+ If `true` the listener will automatically be unbound
11344
11551
  after the first invocation.
11345
11552
 
11346
11553
  @param {Function(event, [element], [data])} listener
@@ -11431,12 +11638,12 @@ document.addEventListener('up:modal:open', (event) => {
11431
11638
 
11432
11639
  @function up.off
11433
11640
  @param {Element|jQuery} [element=document]
11434
- @param {string} events
11641
+ @param {string|Function(): string} events
11435
11642
  @param {string} [selector]
11436
11643
  @param {Function(event, [element], [data])} listener
11437
11644
  The listener function to unbind.
11438
11645
 
11439
- Note that you must pass a reference to the exact same listener function
11646
+ Note that you must pass a reference to the same function reference
11440
11647
  that was passed to `up.on()` earlier.
11441
11648
  @stable
11442
11649
  */
@@ -11687,8 +11894,12 @@ document.addEventListener('up:modal:open', (event) => {
11687
11894
 
11688
11895
  This hyperlink will emit an `user:select` event when clicked:
11689
11896
 
11690
- ```
11691
- <a href='/users/5" up-emit='user:select' up-emit-props='{ "id": 5, "firstName": "Alice" }'>Alice</a>
11897
+ ```html
11898
+ <a href='/users/5'
11899
+ up-emit='user:select'
11900
+ up-emit-props='{ "id": 5, "firstName": "Alice" }'>
11901
+ Alice
11902
+ </a>
11692
11903
 
11693
11904
  <script>
11694
11905
  up.on('a', 'user:select', function(event) {
@@ -11703,6 +11914,7 @@ document.addEventListener('up:modal:open', (event) => {
11703
11914
  The type of the event to be emitted.
11704
11915
  @param [up-emit-props='{}']
11705
11916
  The event properties, serialized as JSON.
11917
+ @stable
11706
11918
  */
11707
11919
  executeEmitAttr = function(event, element) {
11708
11920
  var eventProps, eventType, forkedEvent;
@@ -11771,7 +11983,7 @@ There are existing implementations for various web frameworks:
11771
11983
  - [Roda](https://github.com/adam12/roda-unpoly)
11772
11984
  - [Rack](https://github.com/adam12/rack-unpoly) (Sinatra, Padrino, Hanami, Cuba, ...)
11773
11985
  - [Phoenix](https://elixirforum.com/t/unpoly-a-framework-like-turbolinks/3614/15) (Elixir)
11774
- - [PHP](https://github.com/adam12/rack-unpoly) (Symfony, Laravel, Stack)
11986
+ - [PHP](https://github.com/webstronauts/php-unpoly) (Symfony, Laravel, Stack)
11775
11987
 
11776
11988
  @module up.protocol
11777
11989
  */
@@ -11994,68 +12206,35 @@ There are existing implementations for various web frameworks:
11994
12206
  The timestamp must be explicitely set by the user as an `[up-time]` attribute on the fragment.
11995
12207
  It should indicate the time when the fragment's underlying data was last changed.
11996
12208
 
11997
- Its value is the number of seconds elapsed since the [Unix epoch](https://en.wikipedia.org/wiki/Unix_time).
12209
+ See `[up-time]` for a detailed example.
11998
12210
 
11999
- If no timestamp is known, Unpoly will send a value of zero (`X-Up-Reload-From-Time: 0`).
12000
-
12001
- \#\#\# Example
12002
-
12003
- You may timestamp your fragments with an `[up-time]` attribute to indicate when the underlying data
12004
- was last changed. For instance, when the last message in a list was received from December 24th, 1:51:46 PM UTC:
12211
+ \#\#\# Format
12005
12212
 
12006
- ```html
12007
- <div class="messages" up-time="1608730818">
12008
- ...
12009
- </div>
12010
- ```
12213
+ The time is encoded is the number of seconds elapsed since the [Unix epoch](https://en.wikipedia.org/wiki/Unix_time).
12011
12214
 
12012
- When reloading the `.messages` fragment, Unpoly will echo that timestamp in an `X-Up-Reload-From-Time` header:
12215
+ For instance, a modification date of December 23th, 1:40:18 PM UTC would produce the following header:
12013
12216
 
12014
12217
  ```http
12218
+ X-Up-Target: .unread-count
12015
12219
  X-Up-Reload-From-Time: 1608730818
12016
12220
  ```
12017
12221
 
12018
- \#\# Cheap polling responses
12222
+ If no timestamp is known, Unpoly will send a value of zero (`X-Up-Reload-From-Time: 0`).
12019
12223
 
12020
- A use case for the `X-Up-Reload-From-Time` header is to avoid rendering unchanged content
12021
- while [polling](/up-poll).
12224
+ @header X-Up-Reload-From-Time
12225
+ @stable
12226
+ */
12227
+ contextFromXHR = function(xhr) {
12228
+ return extractHeader(xhr, 'context', JSON.parse);
12229
+ };
12230
+
12231
+ /***
12232
+ This request header contains the targeted layer's [context](/context), serialized as JSON.
12022
12233
 
12023
- The server can compare the time from the request with the time of the last data update.
12024
- If no more recent data is available, the server can [render nothing](/X-Up-Target):
12234
+ The user may choose to not send this header by configuring
12235
+ `up.network.config.requestMetaKeys`.
12025
12236
 
12026
- ```ruby
12027
- class MessagesController < ApplicationController
12028
-
12029
- def index
12030
- if up.reload_from_time == current_user.last_message_at
12031
- up.render_nothing
12032
- else
12033
- @messages = current_user.messages.order(time: :desc).to_a
12034
- render 'index'
12035
- end
12036
- end
12037
-
12038
- end
12039
- ```
12040
-
12041
- Only rendering when needed saves <b>CPU time</b> on your server, which spends most of its response time rendering HTML.
12042
-
12043
- This also reduces the <b>bandwidth cost</b> for a request/response exchange to **~1 KB**.
12044
-
12045
- @header X-Up-Reload-From-Time
12046
- @stable
12047
- */
12048
- contextFromXHR = function(xhr) {
12049
- return extractHeader(xhr, 'context', JSON.parse);
12050
- };
12051
-
12052
- /***
12053
- This request header contains the targeted layer's [context](/up.context), serialized as JSON.
12054
-
12055
- The user may choose to not send this header by configuring
12056
- `up.network.config.requestMetaKeys`.
12057
-
12058
- \#\#\# Example
12237
+ \#\#\# Example
12059
12238
 
12060
12239
  ```http
12061
12240
  X-Up-Context: { "lives": 3 }
@@ -12091,11 +12270,11 @@ There are existing implementations for various web frameworks:
12091
12270
  the request was in flight will get overridden by the server-provided context.
12092
12271
 
12093
12272
  @header X-Up-Context
12094
- @stable
12273
+ @experimental
12095
12274
  */
12096
12275
 
12097
12276
  /***
12098
- This request header contains the [context](/up.context) of the layer
12277
+ This request header contains the [context](/context) of the layer
12099
12278
  targeted for a failed fragment update, serialized as JSON.
12100
12279
 
12101
12280
  A fragment update is considered *failed* if the server responds with a
@@ -12114,7 +12293,7 @@ There are existing implementations for various web frameworks:
12114
12293
  ```
12115
12294
 
12116
12295
  @header X-Up-Fail-Context
12117
- @stable
12296
+ @experimental
12118
12297
  */
12119
12298
 
12120
12299
  /***
@@ -12274,7 +12453,7 @@ There are existing implementations for various web frameworks:
12274
12453
  the response's HTML content.
12275
12454
 
12276
12455
  The header value is the acceptance value serialized as a JSON object.
12277
- To accept an overlay without value, set the header value to `null`.
12456
+ To accept an overlay without value, set the header value to the string `null`.
12278
12457
 
12279
12458
  \#\#\# Example
12280
12459
 
@@ -12320,7 +12499,7 @@ There are existing implementations for various web frameworks:
12320
12499
  the response's HTML content.
12321
12500
 
12322
12501
  The header value is the dismissal value serialized as a JSON object.
12323
- To accept an overlay without value, set the header value to `null`.
12502
+ To accept an overlay without value, set the header value to the string `null`.
12324
12503
 
12325
12504
  \#\#\# Example
12326
12505
 
@@ -12432,10 +12611,12 @@ There are existing implementations for various web frameworks:
12432
12611
  Configures strings used in the optional [server protocol](/up.protocol).
12433
12612
 
12434
12613
  @property up.protocol.config
12614
+
12435
12615
  @param {string} [config.csrfHeader='X-CSRF-Token']
12436
12616
  The name of the HTTP header that will include the
12437
12617
  [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern)
12438
12618
  for AJAX requests.
12619
+
12439
12620
  @param {string|Function(): string} [config.csrfParam]
12440
12621
  The `name` of the hidden `<input>` used for sending a
12441
12622
  [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern) when
@@ -12447,7 +12628,10 @@ There are existing implementations for various web frameworks:
12447
12628
 
12448
12629
  Defaults to the `content` attribute of a `<meta>` tag named `csrf-param`:
12449
12630
 
12450
- <meta name="csrf-param" content="authenticity_token" />
12631
+ ```html
12632
+ <meta name="csrf-param" content="authenticity_token" />
12633
+ ```
12634
+
12451
12635
  @param {string|Function(): string} [config.csrfToken]
12452
12636
  The [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern)
12453
12637
  to send for unsafe requests. The token will be sent as either a HTTP header (for AJAX requests)
@@ -12458,7 +12642,10 @@ There are existing implementations for various web frameworks:
12458
12642
 
12459
12643
  Defaults to the `content` attribute of a `<meta>` tag named `csrf-token`:
12460
12644
 
12461
- <meta name='csrf-token' content='secret12345'>
12645
+ ```
12646
+ <meta name='csrf-token' content='secret12345'>
12647
+ ```
12648
+
12462
12649
  @param {string} [config.methodParam='_method']
12463
12650
  The name of request parameter containing the original request method when Unpoly needs to wrap
12464
12651
  the method.
@@ -12537,13 +12724,14 @@ There are existing implementations for various web frameworks:
12537
12724
  Logging
12538
12725
  =======
12539
12726
 
12540
- Unpoly can print debugging information to the developer console, e.g.:
12727
+ Unpoly can print debugging information to the [browser console](https://developer.chrome.com/docs/devtools/console/), e.g.:
12541
12728
 
12542
12729
  - Which [events](/up.event) are called
12543
12730
  - When we're [making requests to the network](/up.request)
12544
12731
  - Which [compilers](/up.syntax) are applied to which elements
12545
12732
 
12546
- You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12733
+ @see up.log.enable
12734
+ @see up.log.disable
12547
12735
 
12548
12736
  @module up.log
12549
12737
  */
@@ -12651,7 +12839,7 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12651
12839
  return console.log(logo + text);
12652
12840
  }
12653
12841
  };
12654
- up.on('up:framework:boot', printBanner);
12842
+ up.on('up:app:boot', printBanner);
12655
12843
  up.on('up:framework:reset', reset);
12656
12844
  setEnabled = function(value) {
12657
12845
  sessionStore.set('enabled', value);
@@ -12659,7 +12847,7 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12659
12847
  };
12660
12848
 
12661
12849
  /***
12662
- Makes future Unpoly events print vast amounts of debugging information to the developer console.
12850
+ Starts printing debugging information to the developer console.
12663
12851
 
12664
12852
  Debugging information includes which elements are being [compiled](/up.syntax)
12665
12853
  and which [events](/up.event) are being emitted.
@@ -12674,7 +12862,7 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12674
12862
  };
12675
12863
 
12676
12864
  /***
12677
- Prevents future Unpoly events from printing vast amounts of debugging information to the developer console.
12865
+ Stops printing debugging information to the developer console.
12678
12866
 
12679
12867
  Errors will still be printed, even with logging disabled.
12680
12868
 
@@ -12716,24 +12904,26 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12716
12904
  };
12717
12905
 
12718
12906
  /***
12719
- * Registers an empty rejection handler in case the given promise
12720
- * rejects with an AbortError or a failed up.Response.
12721
- *
12722
- * This prevents browsers from printing "Uncaught (in promise)" to the error
12723
- * console when the promise is rejected.
12724
- *
12725
- * This is helpful for event handlers where it is clear that no rejection
12726
- * handler will be registered:
12727
- *
12728
- * up.on('submit', 'form[up-target]', (event, form) => {
12729
- * promise = up.submit(form)
12730
- * up.util.muteRejection(promise)
12731
- * })
12732
- *
12733
- * @function up.log.muteUncriticalRejection
12734
- * @param {Promise} promise
12735
- * @return {Promise}
12736
- * @internal
12907
+ Registers an empty rejection handler in case the given promise
12908
+ rejects with an AbortError or a failed up.Response.
12909
+
12910
+ This prevents browsers from printing "Uncaught (in promise)" to the error
12911
+ console when the promise is rejected.
12912
+
12913
+ This is helpful for event handlers where it is clear that no rejection
12914
+ handler will be registered:
12915
+
12916
+ ```js
12917
+ up.on('submit', 'form[up-target]', (event, form) => {
12918
+ promise = up.submit(form)
12919
+ up.util.muteRejection(promise)
12920
+ })
12921
+ ```
12922
+
12923
+ @function up.log.muteUncriticalRejection
12924
+ @param {Promise} promise
12925
+ @return {Promise}
12926
+ @internal
12737
12927
  */
12738
12928
  muteUncriticalRejection = function(promise) {
12739
12929
  return promise["catch"](function(error) {
@@ -12769,20 +12959,11 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12769
12959
  Custom JavaScript
12770
12960
  =================
12771
12961
 
12772
- Every app needs a way to pair JavaScript snippets with certain HTML elements,
12773
- in order to integrate libraries or implement custom behavior.
12774
-
12775
- Unpoly lets you organize your JavaScript snippets using [compilers](/up.compiler).
12962
+ The `up.syntax` package lets you pair HTML elements with JavaScript behavior.
12776
12963
 
12777
- For instance, to activate the [Masonry](http://masonry.desandro.com/) library for every element
12778
- with a `grid` class, use this compiler:
12779
-
12780
- up.compiler('.grid', function(element) {
12781
- new Masonry(element, { itemSelector: '.grid--item' })
12782
- })
12783
-
12784
- The compiler function will be called on matching elements when the page loads
12785
- or when a matching fragment is [inserted via AJAX](/up.link) later.
12964
+ @see up.compiler
12965
+ @see [up-data]
12966
+ @see up.macro
12786
12967
 
12787
12968
  @module up.syntax
12788
12969
  */
@@ -12817,14 +12998,17 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
12817
12998
  Use compilers to activate your custom Javascript behavior on matching
12818
12999
  elements.
12819
13000
 
12820
- You should migrate your [`DOMContentLoaded`](https://api.jquery.com/ready/)
13001
+ You should migrate your [`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event)
12821
13002
  callbacks to compilers. This will make sure they run both at page load and
12822
13003
  when a new fragment is inserted later.
12823
- It will also organize your JavaScript snippets by selector of affected elements.
13004
+ See [Making JavaScripts work with fragment updates](/legacy-scripts) for advice
13005
+ on migrating legacy scripts.
13006
+
13007
+ It will also organize your JavaScript snippets by selector.
12824
13008
 
12825
13009
  \#\#\# Example
12826
13010
 
12827
- This jQuery compiler will insert the current time into a
13011
+ This compiler will insert the current time into a
12828
13012
  `<div class='current-time'></div>`:
12829
13013
 
12830
13014
  ```js
@@ -12885,55 +13069,34 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
12885
13069
 
12886
13070
  An alternative way to register a destructor function is `up.destructor()`.
12887
13071
 
12888
- \#\#\# Attaching structured data
13072
+ \#\#\# Passing parameters to a compiler
12889
13073
 
12890
- In case you want to attach structured data to the event you're observing,
12891
- you can serialize the data to JSON and put it into an `[up-data]` attribute.
12892
- For instance, a container for a [Google Map](https://developers.google.com/maps/documentation/javascript/tutorial)
12893
- might attach the location and names of its marker pins:
13074
+ Use the `[up-data]` attribute to attach structured data to a DOM element.
13075
+ The data will be parsed and passed to your compiler function.
12894
13076
 
12895
- ```html
12896
- <div class='google-map' up-data='[
12897
- { "lat": 48.36, "lng": 10.99, "title": "Friedberg" },
12898
- { "lat": 48.75, "lng": 11.45, "title": "Ingolstadt" }
12899
- ]'></div>
12900
- ```
13077
+ Alternatively your compiler may access attributes for the compiled element
13078
+ via the standard [`Element#getAttribute()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute)
13079
+ method.
12901
13080
 
12902
- The JSON will be parsed and handed to your compiler as a second argument:
13081
+ Unpoly also provides utility functions to read an element attribute and
13082
+ cast it to a given type:
12903
13083
 
12904
- ```js
12905
- up.compiler('.google-map', function(element, pins) {
12906
- var map = new google.maps.Map(element)
12907
-
12908
- pins.forEach(function(pin) {
12909
- var position = new google.maps.LatLng(pin.lat, pin.lng)
12910
- new google.maps.Marker({
12911
- position: position,
12912
- map: map,
12913
- title: pin.title
12914
- })
12915
- })
12916
- })
12917
- ```
12918
-
12919
- @see legacy-scripts
13084
+ - `up.element.booleanAttr(element, attr)`
13085
+ - `up.element.numberAttr(element, attr)`
13086
+ - `up.element.jsonAttr(element, attr)`
12920
13087
 
12921
13088
  @function up.compiler
12922
13089
  @param {string} selector
12923
13090
  The selector to match.
12924
13091
  @param {number} [options.priority=0]
12925
13092
  The priority of this compiler.
13093
+
12926
13094
  Compilers with a higher priority are run first.
12927
13095
  Two compilers with the same priority are run in the order they were registered.
12928
13096
  @param {boolean} [options.batch=false]
12929
13097
  If set to `true` and a fragment insertion contains multiple
12930
- elements matching the selector, `compiler` is only called once
12931
- with a jQuery collection containing all matching elements.
12932
- @param {boolean} [options.keep=false]
12933
- If set to `true` compiled fragment will be [persisted](/up-keep) during
12934
- fragment updates.
12935
-
12936
- This has the same effect as setting an `up-keep` attribute on the element.
13098
+ elements matching `selector`, the `compiler` function is only called once
13099
+ with all these elements.
12937
13100
  @param {Function(element, data)} compiler
12938
13101
  The function to call when a matching element is inserted.
12939
13102
 
@@ -12970,10 +13133,12 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
12970
13133
  This jQuery compiler will insert the current time into a
12971
13134
  `<div class='current-time'></div>`:
12972
13135
 
12973
- up.$compiler('.current-time', function($element) {
12974
- var now = new Date()
12975
- $element.text(now.toString())
12976
- })
13136
+ ```js
13137
+ up.$compiler('.current-time', function($element) {
13138
+ var now = new Date()
13139
+ $element.text(now.toString())
13140
+ })
13141
+ ```
12977
13142
 
12978
13143
  @function up.$compiler
12979
13144
  @param {string} selector
@@ -12997,33 +13162,40 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
12997
13162
  /***
12998
13163
  Registers a [compiler](/up.compiler) that is run before all other compilers.
12999
13164
 
13000
- Use `up.macro()` to register a compiler that sets multiple Unpoly attributes.
13165
+ A macro lets you set UJS attributes that will be compiled afterwards.
13166
+
13167
+ If you want default attributes for *every* link and form, consider customizing your
13168
+ [navigation options](/navigation).
13001
13169
 
13002
13170
  \#\#\# Example
13003
13171
 
13004
13172
  You will sometimes find yourself setting the same combination of UJS attributes again and again:
13005
13173
 
13006
- <a href="/page1" up-target=".content" up-transition="cross-fade" up-duration="300">Page 1</a>
13007
- <a href="/page2" up-target=".content" up-transition="cross-fade" up-duration="300">Page 2</a>
13008
- <a href="/page3" up-target=".content" up-transition="cross-fade" up-duration="300">Page 3</a>
13174
+ ```html
13175
+ <a href="/page1" up-layer="new modal" up-class="warning" up-animation="shake">Page 1</a>
13176
+ <a href="/page1" up-layer="new modal" up-class="warning" up-animation="shake">Page 1</a>
13177
+ <a href="/page1" up-layer="new modal" up-class="warning" up-animation="shake">Page 1</a>
13178
+ ```
13009
13179
 
13010
- We would much rather define a new `[content-link]` attribute that let's us
13180
+ We would much rather define a new `[smooth-link]` attribute that let's us
13011
13181
  write the same links like this:
13012
13182
 
13013
- <a href="/page1" content-link>Page 1</a>
13014
- <a href="/page2" content-link>Page 2</a>
13015
- <a href="/page3" content-link>Page 3</a>
13183
+ ```html
13184
+ <a href="/page1" smooth-link>Page 1</a>
13185
+ <a href="/page2" smooth-link>Page 2</a>
13186
+ <a href="/page3" smooth-link>Page 3</a>
13187
+ ```
13016
13188
 
13017
13189
  We can define the `[content-link]` attribute by registering a macro that
13018
13190
  sets the `[up-target]`, `[up-transition]` and `[up-duration]` attributes for us:
13019
13191
 
13020
- up.macro('[content-link]', function(link) {
13021
- link.setAttribute('up-target', '.content')
13022
- link.setAttribute('up-transition', 'cross-fade')
13023
- link.setAttribute('up-duration', '300')
13024
- })
13025
-
13026
- Examples for built-in macros are [`a[up-dash]`](/a-up-dash) and [`[up-expand]`](/up-expand).
13192
+ ```
13193
+ up.macro('[smooth-link]', function(link) {
13194
+ link.setAttribute('up-target', '.content')
13195
+ link.setAttribute('up-transition', 'cross-fade')
13196
+ link.setAttribute('up-duration', '300')
13197
+ })
13198
+ ```
13027
13199
 
13028
13200
  @function up.macro
13029
13201
  @param {string} selector
@@ -13056,13 +13228,15 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13056
13228
 
13057
13229
  \#\#\# Example
13058
13230
 
13059
- up.$macro('[content-link]', function($link) {
13060
- $link.attr(
13061
- 'up-target': '.content',
13062
- 'up-transition': 'cross-fade',
13063
- 'up-duration':'300'
13064
- )
13065
- })
13231
+ ```js
13232
+ up.$macro('[content-link]', function($link) {
13233
+ $link.attr(
13234
+ 'up-target': '.content',
13235
+ 'up-transition': 'cross-fade',
13236
+ 'up-duration':'300'
13237
+ )
13238
+ })
13239
+ ```
13066
13240
 
13067
13241
  @function up.$macro
13068
13242
  @param {string} selector
@@ -13124,6 +13298,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13124
13298
 
13125
13299
  /***
13126
13300
  Applies all compilers on the given element and its descendants.
13301
+
13127
13302
  Unlike [`up.hello()`](/up.hello), this doesn't emit any events.
13128
13303
 
13129
13304
  @function up.syntax.compile
@@ -13152,8 +13327,8 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13152
13327
  })
13153
13328
  ```
13154
13329
 
13155
- An alternative way to register a destructor function is to `return`
13156
- it from your compiler function.
13330
+ An alternative way to register a destructor function is to
13331
+ [`return` it from your compiler function](/up.compiler#cleaning-up-after-yourself).
13157
13332
 
13158
13333
  @function up.destructor
13159
13334
  @param {Element} element
@@ -13177,6 +13352,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13177
13352
 
13178
13353
  /***
13179
13354
  Runs any destructor on the given fragment and its descendants in the same layer.
13355
+
13180
13356
  Unlike [`up.destroy()`](/up.destroy), this does not emit any events
13181
13357
  and does not remove the element from the DOM.
13182
13358
 
@@ -13195,20 +13371,23 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13195
13371
  };
13196
13372
 
13197
13373
  /***
13198
- Checks if the given element has an [`up-data`](/up-data) attribute.
13199
- If yes, parses the attribute value as JSON and returns the parsed object.
13374
+ Returns the given element's `[up-data]`, parsed as a JavaScript object.
13200
13375
 
13201
- Returns `undefined` if the element has no `up-data` attribute.
13376
+ Returns `undefined` if the element has no `[up-data]` attribute.
13202
13377
 
13203
13378
  \#\#\# Example
13204
13379
 
13205
13380
  You have an element with JSON data serialized into an `up-data` attribute:
13206
13381
 
13207
- <span class='person' up-data='{ "age": 18, "name": "Bob" }'>Bob</span>
13382
+ ```html
13383
+ <span class='person' up-data='{ "age": 18, "name": "Bob" }'>Bob</span>
13384
+ ```
13208
13385
 
13209
13386
  Calling `up.syntax.data()` will deserialize the JSON string into a JavaScript object:
13210
13387
 
13211
- up.syntax.data('.person') // returns { age: 18, name: 'Bob' }
13388
+ ```js
13389
+ up.syntax.data('.person') // returns { age: 18, name: 'Bob' }
13390
+ ```
13212
13391
 
13213
13392
  @function up.data
13214
13393
  @param {string|Element|jQuery} element
@@ -13221,39 +13400,49 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13221
13400
  */
13222
13401
 
13223
13402
  /***
13224
- If an element with an `up-data` attribute enters the DOM,
13403
+ Attaches structured data to an element, to be consumed by a compiler.
13404
+
13405
+ If an element with an `[up-data]` attribute enters the DOM,
13225
13406
  Unpoly will parse the JSON and pass the resulting object to any matching
13226
- [`up.compiler()`](/up.compiler) handlers.
13407
+ [`up.compiler()`](/up.compiler) functions.
13408
+
13409
+ \#\#\# Example
13227
13410
 
13228
13411
  For instance, a container for a [Google Map](https://developers.google.com/maps/documentation/javascript/tutorial)
13229
13412
  might attach the location and names of its marker pins:
13230
13413
 
13231
- <div class='google-map' up-data='[
13232
- { "lat": 48.36, "lng": 10.99, "title": "Friedberg" },
13233
- { "lat": 48.75, "lng": 11.45, "title": "Ingolstadt" }
13234
- ]'></div>
13414
+ ```html
13415
+ <div class='google-map' up-data='[
13416
+ { "lat": 48.36, "lng": 10.99, "title": "Friedberg" },
13417
+ { "lat": 48.75, "lng": 11.45, "title": "Ingolstadt" }
13418
+ ]'></div>
13419
+ ```
13235
13420
 
13236
13421
  The JSON will be parsed and handed to your compiler as a second argument:
13237
13422
 
13238
- up.compiler('.google-map', function(element, pins) {
13239
- var map = new google.maps.Map(element)
13240
- pins.forEach(function(pin) {
13241
- var position = new google.maps.LatLng(pin.lat, pin.lng)
13242
- new google.maps.Marker({
13243
- position: position,
13244
- map: map,
13245
- title: pin.title
13246
- })
13247
- })
13423
+ ```js
13424
+ up.compiler('.google-map', function(element, pins) {
13425
+ var map = new google.maps.Map(element)
13426
+ pins.forEach(function(pin) {
13427
+ var position = new google.maps.LatLng(pin.lat, pin.lng)
13428
+ new google.maps.Marker({
13429
+ position: position,
13430
+ map: map,
13431
+ title: pin.title
13248
13432
  })
13433
+ })
13434
+ })
13435
+ ```
13249
13436
 
13250
13437
  Similarly, when an event is triggered on an element annotated with
13251
13438
  [`up-data`], the parsed object will be passed to any matching
13252
13439
  [`up.on()`](/up.on) handlers.
13253
13440
 
13254
- up.on('click', '.google-map', function(event, element, pins) {
13255
- console.log("There are %d pins on the clicked map", pins.length)
13256
- })
13441
+ ```js
13442
+ up.on('click', '.google-map', function(event, element, pins) {
13443
+ console.log("There are %d pins on the clicked map", pins.length)
13444
+ })
13445
+ ```
13257
13446
 
13258
13447
  @selector [up-data]
13259
13448
  @param up-data
@@ -13306,9 +13495,10 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13306
13495
  History
13307
13496
  ========
13308
13497
 
13309
- In an Unpoly app, every page has an URL.
13498
+ The `up.history` module helps you work with the browser history.
13310
13499
 
13311
- [Fragment updates](/up.link) automatically update the URL.
13500
+ @see up.history.location
13501
+ @see up:location:changed
13312
13502
 
13313
13503
  @module up.history
13314
13504
  */
@@ -13333,7 +13523,7 @@ In an Unpoly app, every page has an URL.
13333
13523
  Defines whether [fragment updates](/up.render) will update the browser's current URL.
13334
13524
 
13335
13525
  If set to `false` Unpoly will never change the browser URL.
13336
- @param {boolean} [config.restoreScroll=true]
13526
+ @param {boolean} [config.enabled=true]
13337
13527
  Whether to restore the known scroll positions
13338
13528
  when the user goes back or forward in history.
13339
13529
  @stable
@@ -13442,7 +13632,7 @@ In an Unpoly app, every page has an URL.
13442
13632
  address bar with the given URL.
13443
13633
 
13444
13634
  When the user restores the new history entry later,
13445
- Unpoly will replace the document body with the body from that URL.
13635
+ Unpoly will replace a selector from `up.history.config.restoreTargets` with the body from that URL.
13446
13636
 
13447
13637
  Note that [fragment navigation](/navigation) will automatically update the
13448
13638
  browser's location bar for you.
@@ -13476,7 +13666,7 @@ In an Unpoly app, every page has an URL.
13476
13666
 
13477
13667
  When a [layer](/up.layer) has no [visible history](/up.Layer.prototype.historyVisible), following a link
13478
13668
  will not cause the browser's address bar to be updated. In this case no `up:location:changed` event will be emitted.
13479
- There will however be an `up:layer:location:changed` event be emitted.
13669
+ However, a `up:layer:location:changed` will be emitted even if the address bar did not change.
13480
13670
 
13481
13671
  @event up:location:changed
13482
13672
  @param {string} event.url
@@ -13549,9 +13739,11 @@ In an Unpoly app, every page has an URL.
13549
13739
  register = function() {
13550
13740
  window.history.scrollRestoration = 'manual';
13551
13741
  window.addEventListener('popstate', pop);
13552
- return replace(currentLocation(), {
13553
- event: false
13554
- });
13742
+ if (up.protocol.initialRequestMethod() === 'GET') {
13743
+ return replace(currentLocation(), {
13744
+ event: false
13745
+ });
13746
+ }
13555
13747
  };
13556
13748
  if (typeof jasmine !== "undefined" && jasmine !== null) {
13557
13749
  return register();
@@ -13614,31 +13806,48 @@ In an Unpoly app, every page has an URL.
13614
13806
  })();
13615
13807
 
13616
13808
  }).call(this);
13809
+ (function() {
13810
+ var e, u,
13811
+ slice = [].slice;
13617
13812
 
13618
- /***
13619
- Fragment update API
13620
- ===================
13621
-
13622
- The `up.fragment` module exposes a high-level Javascript API to [update](/up.replace) or
13623
- [destroy](/up.destroy) page fragments.
13813
+ u = up.util;
13624
13814
 
13625
- Fragments are [compiled](/up.compiler) elements that can be updated from a server URL.
13626
- They also exist on a layer (page, modal, popup).
13815
+ e = up.element;
13627
13816
 
13628
- Most of Unpoly's functionality (like [fragment links](/up.link) or [modals](/up.modal))
13629
- is built from `up.fragment` functions. You may use them to extend Unpoly from your
13630
- [custom Javascript](/up.syntax).
13631
13817
 
13632
- @module up.fragment
13633
- */
13634
-
13635
- (function() {
13636
- var slice = [].slice;
13818
+ /***
13819
+ Fragment API
13820
+ ===========
13821
+
13822
+ The `up.fragment` module offers a high-level JavaScript API to work with DOM elements.
13823
+
13824
+ A fragment is an element with some additional properties that are useful in the context of
13825
+ a server-rendered web application:
13826
+
13827
+ - Fragments are [identified by a CSS selector](/up.fragment.toTarget), like a `.class` or `#id`.
13828
+ - Fragments are usually updated by a [link](/a-up-follow) for [form](/form-up-submits) that targets their selector.
13829
+ When the server renders HTML with a matching element, the fragment is swapped with a new version.
13830
+ - As fragments enter the page they are automatically [compiled](/up.compiler) to activate JavaScript behavior.
13831
+ - Fragment changes may be [animated](/up.motion).
13832
+ - Fragments are placed on a [layer](/up.layer) that is isolated from other layers.
13833
+ Unpoly features will only see or change fragments from the [current layer](/up.layer.current)
13834
+ unless you [explicitly target another layer](/layer-option).
13835
+ - Fragments [know the URL from where they were loaded](/up.source).
13836
+ They can be [reloaded](/up.reload) or [polled periodically](/up-polled).
13837
+
13838
+ For low-level DOM utilities that complement the browser's native API, see `up.element`.
13839
+
13840
+ @see up.render
13841
+ @see up.navigate
13842
+ @see up.destroy
13843
+ @see up.reload
13844
+ @see up.fragment.get
13845
+ @see up.hello
13846
+
13847
+ @module up.fragment
13848
+ */
13637
13849
 
13638
13850
  up.fragment = (function() {
13639
- var CSS_HAS_SUFFIX_PATTERN, closest, config, contains, destroy, e, emitFragmentDestroyed, emitFragmentInserted, emitFragmentKeep, emitFragmentKept, emitFromKeepPlan, expandTargets, failKey, getAll, getDumb, getSmart, getSubtree, hasAutoHistory, hello, isDestroying, isGoodClassForTarget, isNotDestroying, markFragmentAsDestroying, matches, navigate, parseSelector, parseTargetAndOptions, reload, render, renderLocalContent, renderRemoteContent, reset, resolveOriginReference, sourceOf, successKey, timeOf, toTarget, u, visit;
13640
- u = up.util;
13641
- e = up.element;
13642
13851
 
13643
13852
  /***
13644
13853
  Configures defaults for fragment updates.
@@ -13684,7 +13893,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13684
13893
  The default configuration tries, in this order:
13685
13894
 
13686
13895
  - If the URL has a `#hash`, scroll to the hash.
13687
- - If updating a [main target](/main), reset scroll positions.
13896
+ - If updating a [main target](/up-main), reset scroll positions.
13688
13897
 
13689
13898
  @param {boolean|string|Function(Element)} [config.autoFocus]
13690
13899
  How to focus when updating a fragment with `{ focus: 'auto' }`.
@@ -13696,7 +13905,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13696
13905
  - Focus a `#hash` in the URL.
13697
13906
  - Focus an `[autofocus]` element in the new fragment.
13698
13907
  - If focus was lost with the old fragment, focus the new fragment.
13699
- - If updating a [main target](/main), focus the new fragment.
13908
+ - If updating a [main target](/up-main), focus the new fragment.
13700
13909
 
13701
13910
  @param {boolean} [config.runScripts=false]
13702
13911
  Whether to execute `<script>` tags in updated fragments.
@@ -13704,7 +13913,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13704
13913
  Scripts will load asynchronously, with no guarantee of execution order.
13705
13914
 
13706
13915
  If you set this to `true`, mind that the `<body>` element is a default
13707
- [main target](/main). If you are including your global application scripts
13916
+ [main target](/up-main). If you are including your global application scripts
13708
13917
  at the end of your `<body>`
13709
13918
  for performance reasons, swapping the `<body>` will re-execute these scripts.
13710
13919
  In that case you must configure a different main target that does not include
@@ -13712,6 +13921,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13712
13921
 
13713
13922
  @stable
13714
13923
  */
13924
+ var CSS_HAS_SUFFIX_PATTERN, closest, config, contains, destroy, emitFragmentDestroyed, emitFragmentInserted, emitFragmentKeep, emitFragmentKept, emitFromKeepPlan, expandTargets, failKey, getAll, getDumb, getSmart, getSubtree, hasAutoHistory, hello, isDestroying, isGoodClassForTarget, isNotDestroying, markFragmentAsDestroying, matches, navigate, parseSelector, parseTargetAndOptions, reload, render, renderLocalContent, renderRemoteContent, reset, resolveOriginReference, sourceOf, successKey, timeOf, toTarget, visit;
13715
13925
  config = new up.Config(function() {
13716
13926
  return {
13717
13927
  badTargetClasses: [/^up-/],
@@ -13732,13 +13942,8 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13732
13942
  autoScroll: ['hash', 'layer-if-main']
13733
13943
  };
13734
13944
  });
13735
- Object.defineProperty(config, 'mainTargets', {
13736
- get: function() {
13737
- return up.layer.config.any.mainTargets;
13738
- },
13739
- set: function(value) {
13740
- return up.layer.config.any.mainTargets = value;
13741
- }
13945
+ u.delegate(config, 'mainTargets', function() {
13946
+ return up.layer.config.any;
13742
13947
  });
13743
13948
  reset = function() {
13744
13949
  return config.reset();
@@ -13792,6 +13997,74 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13792
13997
  return e.closestAttr(element, 'up-time') || '0';
13793
13998
  };
13794
13999
 
14000
+ /***
14001
+ Sets the time when the fragment's underlying data was last changed.
14002
+
14003
+ This can be used to avoid rendering unchanged HTML when [reloading](/up.reload)
14004
+ a fragment. This saves <b>CPU time</b> and reduces the <b>bandwidth cost</b> for a
14005
+ request/response exchange to **~1 KB**.
14006
+
14007
+ \#\# Example
14008
+
14009
+ Let's say we display a list of recent messages.
14010
+ We use the `[up-poll]` attribute to reload the `.messages` fragment every 30 seconds:
14011
+
14012
+ ```html
14013
+ <div class="messages" up-poll>
14014
+ ...
14015
+ </div>
14016
+ ```
14017
+
14018
+ The list is now always up to date. But most of the time there will not be new messages,
14019
+ and we waste resources sending the same unchanged HTML from the server.
14020
+
14021
+ We can improve this by setting an `[up-time]` attribute and the message list.
14022
+ The attribute value is the time of the most recent message.
14023
+
14024
+ The time is encoded as the number of seconds since [Unix epoch](https://en.wikipedia.org/wiki/Unix_time).
14025
+ When, for instance, the last message in a list was received from December 24th, 1:51:46 PM UTC,
14026
+ we use the following HTML:
14027
+
14028
+ ```html
14029
+ <div class="messages" up-time="1608730818" up-poll>
14030
+ ...
14031
+ </div>
14032
+ ```
14033
+
14034
+ When reloading Unpoly will echo the `[up-time]` timestamp in an `X-Up-Reload-From-Time` header:
14035
+
14036
+ ```http
14037
+ X-Up-Reload-From-Time: 1608730818
14038
+ ```
14039
+
14040
+ The server can compare the time from the request with the time of the last data update.
14041
+ If no more recent data is available, the server can render nothing and respond with
14042
+ an [`X-Up-Target: :none`](/X-Up-Target) header.
14043
+
14044
+ Here is an example with [unpoly-rails](https://unpoly.com/install/rails):
14045
+
14046
+ ```ruby
14047
+ class MessagesController < ApplicationController
14048
+
14049
+ def index
14050
+ if up.reload_from_time == current_user.last_message_at
14051
+ up.render_nothing
14052
+ else
14053
+ @messages = current_user.messages.order(time: :desc).to_a
14054
+ render 'index'
14055
+ end
14056
+ end
14057
+
14058
+ end
14059
+ ```
14060
+
14061
+ @selector [up-time]
14062
+ @param {string} up-time
14063
+ The number of seconds between the [Unix epoch](https://en.wikipedia.org/wiki/Unix_time).
14064
+ and the time when the element's underlying data was last changed.
14065
+ @experimental
14066
+ */
14067
+
13795
14068
  /***
13796
14069
  Sets this element's source URL for [reloading](/up.reload) and [polling](/up-poll)
13797
14070
 
@@ -13813,7 +14086,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13813
14086
  </div>
13814
14087
 
13815
14088
  @selector [up-source]
13816
- @param {String} up-source
14089
+ @param {string} up-source
13817
14090
  The URL from which to reload this element.
13818
14091
  @stable
13819
14092
  */
@@ -13823,7 +14096,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13823
14096
 
13824
14097
  The current and new elements must both match the same CSS selector.
13825
14098
  The selector is either given as `{ target }` option,
13826
- or a [main target](/main) is used as default.
14099
+ or a [main target](/up-main) is used as default.
13827
14100
 
13828
14101
  See the [fragment placement](/fragment-placement) selector for many examples for how you can target content.
13829
14102
 
@@ -13884,29 +14157,32 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13884
14157
 
13885
14158
  @function up.render
13886
14159
 
13887
- @param {string|Element|jQuery} [target]
14160
+ @param {string|Element|jQuery|Array<string>} [target]
13888
14161
  The CSS selector to update.
13889
14162
 
13890
- If omitted a [main target](/main) will be rendered.
14163
+ If omitted a [main target](/up-main) will be rendered.
13891
14164
 
13892
- You can also pass a DOM element or jQuery element here, in which case a selector
14165
+ You may also pass a DOM element or jQuery element here, in which case a selector
13893
14166
  will be [inferred from the element attributes](/up.fragment.toTarget). The given element
13894
14167
  will also be used as [`{ origin }`](#options.origin) for the fragment update.
13895
14168
 
14169
+ You may also pass an array of selector alternatives. The first selector
14170
+ matching in both old and new content will be used.
14171
+
13896
14172
  Instead of passing the target as the first argument, you may also pass it as
13897
14173
  a [´{ target }`](#options.target) option..
13898
14174
 
13899
- @param {string|Element|jQuery} [options.target]
14175
+ @param {string|Element|jQuery|Array<string>} [options.target]
13900
14176
  The CSS selector to update.
13901
14177
 
13902
- If omitted a [main target](/main) will be rendered.
14178
+ See documentation for the [`target`](#target) parameter.
13903
14179
 
13904
14180
  @param {string|boolean} [options.fallback=false]
13905
14181
  Specifies behavior if the [target selector](/up.render#options.target) is missing from the current page or the server response.
13906
14182
 
13907
14183
  If set to a CSS selector string, Unpoly will attempt to replace that selector instead.
13908
14184
 
13909
- If set to `true` Unpoly will attempt to replace a [main target](/main) instead.
14185
+ If set to `true` Unpoly will attempt to replace a [main target](/up-main) instead.
13910
14186
 
13911
14187
  If set to `false` Unpoly will immediately reject the render promise.
13912
14188
 
@@ -13986,12 +14262,12 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13986
14262
 
13987
14263
  If set to `'auto'` history will be updated if the `{ target }` matches
13988
14264
  a selector in `up.fragment.config.autoHistoryTargets`. By default this contains all
13989
- [main targets](/main).
14265
+ [main targets](/up-main).
13990
14266
 
13991
14267
  If set to `false`, the history will remain unchanged.
13992
14268
 
13993
14269
  [Overlays](/up.layer) will only change the browser URL and window title if the overlay
13994
- has [visible history](/up.layer.historyVisible), even with `{ history: true }`.
14270
+ has [visible history](/up.layer.historyVisible), even when `{ history: true }` is passed.
13995
14271
 
13996
14272
  @param {string} [options.title]
13997
14273
  An explicit document title to use after rendering.
@@ -14042,11 +14318,12 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14042
14318
  Also see [`up.request({ cache })`](/up.request#options.cache).
14043
14319
 
14044
14320
  @param {boolean|string} [options.clearCache]
14045
- Whether existing [cache](/up.cache) entries will be cleared with this request.
14321
+ Whether existing [cache](/up.cache) entries will be [cleared](/up.cache.clear) with this request.
14046
14322
 
14047
- By default a non-GET request will clear the entire cache.
14048
14323
  You may also pass a [URL pattern](/url-patterns) to only clear matching requests.
14049
14324
 
14325
+ By default a non-GET request will clear the entire cache.
14326
+
14050
14327
  Also see [`up.request({ clearCache })`](/up.request#options.clearCache) and `up.network.config.clearCache`.
14051
14328
 
14052
14329
  @param {Element|jQuery} [options.origin]
@@ -14071,7 +14348,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14071
14348
  This is only relevant when updating a layer that is not the [frontmost layer](/up.layer.front).
14072
14349
 
14073
14350
  @param {Object} [options.context]
14074
- An object that will be merged into the [context](/up.context) of the current layer once the fragment is rendered.
14351
+ An object that will be merged into the [context](/context) of the current layer once the fragment is rendered.
14075
14352
 
14076
14353
  @param {boolean} [options.keep=true]
14077
14354
  Whether [`[up-keep]`](/up-keep) elements will be preserved in the updated fragment.
@@ -14175,7 +14452,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14175
14452
  @param {string|Element|jQuery} [target]
14176
14453
  The CSS selector to update.
14177
14454
 
14178
- If omitted a [main target](/main) will be rendered.
14455
+ If omitted a [main target](/up-main) will be rendered.
14179
14456
 
14180
14457
  You can also pass a DOM element or jQuery element here, in which case a selector
14181
14458
  will be [inferred from the element attributes](/up.fragment.target). The given element
@@ -14205,17 +14482,19 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14205
14482
  an entirely different page layout (like a maintenance page or fatal server error)
14206
14483
  which should be open with a full page load:
14207
14484
 
14208
- up.on('up:fragment:loaded', (event) => {
14209
- let isMaintenancePage = event.response.getHeader('X-Maintenance')
14485
+ ```js
14486
+ up.on('up:fragment:loaded', (event) => {
14487
+ let isMaintenancePage = event.response.getHeader('X-Maintenance')
14210
14488
 
14211
- if (isMaintenancePage) {
14212
- // Prevent the fragment update and don't update browser history
14213
- event.preventDefault()
14489
+ if (isMaintenancePage) {
14490
+ // Prevent the fragment update and don't update browser history
14491
+ event.preventDefault()
14214
14492
 
14215
- // Make a full page load for the same request.
14216
- event.request.loadPage()
14217
- }
14218
- })
14493
+ // Make a full page load for the same request.
14494
+ event.request.loadPage()
14495
+ }
14496
+ })
14497
+ ```
14219
14498
 
14220
14499
  Instead of preventing the update, listeners may also access the `event.renderOptions` object
14221
14500
  to mutate options to the `up.render()` call that will process the server response.
@@ -14229,6 +14508,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14229
14508
  The server response.
14230
14509
  @param {Object} event.renderOptions
14231
14510
  Options for the `up.render()` call that will process the server response.
14511
+ @stable
14232
14512
  */
14233
14513
 
14234
14514
  /***
@@ -14614,7 +14894,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14614
14894
  - The [`up.element.all()`](/up.element.get) function simply returns the all elements matching a selector
14615
14895
  without further filtering.
14616
14896
 
14617
- @function up.fragment.get
14897
+ @function up.fragment.all
14618
14898
 
14619
14899
  @param {Element|jQuery} [root=document]
14620
14900
  The root element for the search. Only the root's children will be matched.
@@ -14849,7 +15129,8 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14849
15129
 
14850
15130
  \#\#\# Skipping updates when nothing changed
14851
15131
 
14852
- TODO: Document [up-time] and X-Up-Reload-From-Time (currently both documented in `X-Up-Reload-From-Time`).
15132
+ You may use the `[up-time]` attribute to avoid rendering unchanged HTML when reloading
15133
+ a fragment. See `[up-time]` for a detailed example.
14853
15134
 
14854
15135
  @function up.reload
14855
15136
  @param {string|Element|jQuery} [target]
@@ -14927,11 +15208,12 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14927
15208
 
14928
15209
  \#\#\# Example
14929
15210
 
14930
- element = document.createElement('span')
14931
- element.className = 'klass'
14932
- selector = up.fragment.toTarget(element) // returns '.klass'
15211
+ ```js
15212
+ element = up.element.createFromHTML('<span class="klass">...</span>')
15213
+ selector = up.fragment.toTarget(element) // returns '.klass'
15214
+ ```
14933
15215
 
14934
- @function up.element.toTarget
15216
+ @function up.fragment.toTarget
14935
15217
  @param {string|Element|jQuery}
14936
15218
  The element for which to create a selector.
14937
15219
  @stable
@@ -14954,7 +15236,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14954
15236
  selector = '';
14955
15237
  for (i = 0, len = goodClasses.length; i < len; i++) {
14956
15238
  klass = goodClasses[i];
14957
- selector += "." + klass;
15239
+ selector += e.classSelector(klass);
14958
15240
  }
14959
15241
  return selector;
14960
15242
  } else {
@@ -15104,10 +15386,13 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
15104
15386
  When no other render target is given, Unpoly will try to find and replace a main target.
15105
15387
 
15106
15388
  In most app layouts the main target should match the primary content area.
15107
- The default main targets are the HTML5 [`<main>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main) element,
15108
- any element with an `[up-main]` attribute and the current layer's
15109
- [topmost swappable element](/main). You may configure main target selectors
15110
- in `up.fragment.config.mainTargets`.
15389
+ The default main targets are:
15390
+
15391
+ - any element with an `[up-main]` attribute
15392
+ - the HTML5 [`<main>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main) element
15393
+ - the current layer's [topmost swappable element](/layer)
15394
+
15395
+ You may configure main target selectors in `up.fragment.config.mainTargets`.
15111
15396
 
15112
15397
  \#\#\# Example
15113
15398
 
@@ -15119,6 +15404,86 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
15119
15404
  @experimental
15120
15405
  */
15121
15406
 
15407
+ /***
15408
+ Updates this element when no other render target is given.
15409
+
15410
+ \#\#\# Example
15411
+
15412
+ Many links simply replace the main content element in your application layout.
15413
+
15414
+ Unpoly lets you mark this elements as a default target using the `[up-main]` attribute:
15415
+
15416
+ ```html
15417
+ <body>
15418
+ <div class="layout">
15419
+ <div class="layout--side">
15420
+ ...
15421
+ </div>
15422
+ <div class="layout--content" up-main>
15423
+ ...
15424
+ </div>
15425
+ </div>
15426
+ </body>
15427
+ ```
15428
+
15429
+ Once a main target is configured, you no longer need `[up-target]` in a link.\
15430
+ Use `[up-follow]` and the `[up-main]` element will be replaced:
15431
+
15432
+ ```html
15433
+ <a href="/foo" up-follow>...</a>
15434
+ ```
15435
+
15436
+ If you want to update something more specific, you can still use `[up-target]`:
15437
+
15438
+ ```html
15439
+ <a href="/foo" up-target=".profile">...</a>
15440
+ ```
15441
+
15442
+ Instead of assigning `[up-main]` you may also configure an existing selector in `up.fragment.config.mainTargets`:
15443
+
15444
+ ```js
15445
+ up.fragment.config.mainTargets.push('.layout--content')
15446
+ ```
15447
+
15448
+ Overlays can use different main targets
15449
+ ---------------------------------------
15450
+
15451
+ Overlays often use a different default selector, e.g. to exclude a navigation bar.
15452
+
15453
+ To define a different main target for an overlay, set the [layer mode](/layer-terminology) as the
15454
+ value of the `[up-main]` attribute:
15455
+
15456
+ ```html
15457
+ <body>
15458
+ <div class="layout" up-main="root">
15459
+ <div class="layout--side">
15460
+ ...
15461
+ </div>
15462
+ <div class="layout--content" up-main="modal">
15463
+ ...
15464
+ </div>
15465
+ </div>
15466
+ </body>
15467
+ ```
15468
+
15469
+ Instead of assigning `[up-main]` you may also configure layer-specific targets in `up.layer.config`:
15470
+
15471
+ ```js
15472
+ up.layer.config.popup.mainTargets.push('.menu') // for popup overlays
15473
+ up.layer.config.drawer.mainTargets.push('.menu') // for drawer overlays
15474
+ up.layer.config.overlay.mainTargets.push('.layout--content') // for all overlay modes
15475
+ ```
15476
+
15477
+ @selector [up-main]
15478
+ @param [up-main]
15479
+ A space-separated list of [layer modes](/layer-terminology) for which to use this main target.
15480
+
15481
+ Omit the attribute value to define a main target for *all* layer modes.
15482
+
15483
+ To use a different main target for all overlays (but not the root layer), set `[up-main=overlay]`.
15484
+ @stable
15485
+ */
15486
+
15122
15487
  /***
15123
15488
  To make a server request without changing a fragment, use the `:none` selector.
15124
15489
 
@@ -15163,7 +15528,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
15163
15528
  For the [root layer](/up.layer.root) it is the `<body>` element. For an overlay
15164
15529
  it is the target with which the overlay was opened with.
15165
15530
 
15166
- In canonical usage the topmost swappable element is often a [main element](/main).
15531
+ In canonical usage the topmost swappable element is often a [main element](/up-main).
15167
15532
 
15168
15533
  \#\#\# Example
15169
15534
 
@@ -15260,36 +15625,39 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
15260
15625
 
15261
15626
  up.visit = up.fragment.visit;
15262
15627
 
15628
+
15629
+ /***
15630
+ Returns the current [context](/context).
15631
+
15632
+ This is aliased as `up.layer.context`.
15633
+
15634
+ @property up.context
15635
+ @param {Object} context
15636
+ The context object.
15637
+
15638
+ If no context has been set an empty object is returned.
15639
+ @experimental
15640
+ */
15641
+
15642
+ u.delegate(up, 'context', function() {
15643
+ return up.layer.current;
15644
+ });
15645
+
15263
15646
  }).call(this);
15264
15647
 
15265
15648
  /***
15266
15649
  Scrolling viewports
15267
15650
  ===================
15268
15651
 
15269
- The `up.viewport` module controls the scroll position of scrollable containers ("viewports").
15652
+ The `up.viewport` module controls the scroll position and focus within scrollable containers ("viewports").
15270
15653
 
15271
15654
  The default viewport for any web application is the main document. An application may
15272
15655
  define additional viewports by giving the CSS property `{ overflow-y: scroll }` to any `<div>`.
15273
15656
 
15657
+ Also see documentation for the [scroll option](/scroll-option) and [focus option](focus-option).
15274
15658
 
15275
- \#\#\# Revealing new content
15276
-
15277
- When following a [link to a fragment](/a-up-follow) Unpoly will automatically
15278
- scroll the document's viewport to [reveal](/up.viewport) the updated content.
15279
-
15280
- You should [make Unpoly aware](/up.viewport.config#config.fixedTop) of fixed elements in your
15281
- layout, such as navigation bars or headers. Unpoly will respect these sticky
15282
- elements when [revealing updated fragments](/up.reveal).
15283
-
15284
- You should also [tell Unpoly](/up.viewport.config#config.viewportSelectors) when your application has more than one viewport,
15285
- so Unpoly can pick the right viewport to scroll for each fragment update.
15286
-
15287
-
15288
- \#\#\# Bootstrap integration
15289
-
15290
- When using Bootstrap integration (`unpoly-bootstrap3.js` and `unpoly-bootstrap3.css`)
15291
- Unpoly will automatically be aware of sticky Bootstrap components such as
15292
- [fixed navbar](https://getbootstrap.com/examples/navbar-fixed-top/).
15659
+ @see up.reveal
15660
+ @see [up-fixed=top]
15293
15661
 
15294
15662
  @module up.viewport
15295
15663
  */
@@ -15298,29 +15666,31 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15298
15666
  var slice = [].slice;
15299
15667
 
15300
15668
  up.viewport = (function() {
15301
- var absolutize, allSelector, anchoredRight, autofocus, closest, config, doFocus, e, f, firstHashTarget, fixedElements, getAll, getAround, getRoot, getScrollTops, getSubtree, isNativelyFocusable, isRoot, makeFocusable, parseOptions, pureHash, reset, resetScroll, restoreScroll, reveal, revealHash, rootHasReducedWidthFromScrollbar, rootHeight, rootOverflowElement, rootSelector, rootWidth, saveScroll, scroll, scrollTopKey, scrollTops, scrollbarWidth, scrollingController, setScrollTops, tryFocus, u, userScrolled, wasChosenAsOverflowingElement;
15669
+ var absolutize, allSelector, anchoredRight, closest, config, doFocus, e, f, firstHashTarget, fixedElements, getAll, getAround, getRoot, getScrollTops, getSubtree, isNativelyFocusable, isRoot, makeFocusable, parseOptions, pureHash, reset, resetScroll, restoreScroll, reveal, revealHash, rootHasReducedWidthFromScrollbar, rootHeight, rootOverflowElement, rootSelector, rootWidth, saveScroll, scroll, scrollTopKey, scrollTops, scrollbarWidth, scrollingController, setScrollTops, tryFocus, u, userScrolled, wasChosenAsOverflowingElement;
15302
15670
  u = up.util;
15303
15671
  e = up.element;
15304
15672
  f = up.fragment;
15305
15673
 
15306
15674
  /***
15307
- Configures the application layout.
15675
+ Configures defaults for scrolling.
15308
15676
 
15309
15677
  @property up.viewport.config
15310
15678
  @param {Array} [config.viewportSelectors]
15311
- An array of CSS selectors that find viewports
15312
- (containers that scroll their contents).
15679
+ An array of CSS selectors that match viewports.
15313
15680
  @param {Array} [config.fixedTop]
15314
15681
  An array of CSS selectors that find elements fixed to the
15315
15682
  top edge of the screen (using `position: fixed`).
15683
+
15316
15684
  See [`[up-fixed="top"]`](/up-fixed-top) for details.
15317
15685
  @param {Array} [config.fixedBottom]
15318
- An array of CSS selectors that find elements fixed to the
15686
+ An array of CSS selectors that match elements fixed to the
15319
15687
  bottom edge of the screen (using `position: fixed`).
15688
+
15320
15689
  See [`[up-fixed="bottom"]`](/up-fixed-bottom) for details.
15321
15690
  @param {Array} [config.anchoredRight]
15322
15691
  An array of CSS selectors that find elements anchored to the
15323
15692
  right edge of the screen (using `right:0` with `position: fixed` or `position: absolute`).
15693
+
15324
15694
  See [`[up-anchored="right"]`](/up-anchored-right) for details.
15325
15695
  @param {number} [config.revealSnap]
15326
15696
  When [revealing](/up.reveal) elements, Unpoly will scroll an viewport
@@ -15434,19 +15804,9 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15434
15804
  };
15435
15805
 
15436
15806
  /***
15437
- Scroll's the given element's viewport so the first rows of the
15807
+ Scrolls the given element's viewport so the first rows of the
15438
15808
  element are visible for the user.
15439
15809
 
15440
- \#\#\# How Unpoly finds the viewport
15441
-
15442
- The viewport (the container that is going to be scrolled)
15443
- is the closest parent of the element that is either:
15444
-
15445
- - the currently open [modal](/up.modal)
15446
- - an element with the attribute `[up-viewport]`
15447
- - the `<body>` element
15448
- - an element matching the selector you have configured using `up.viewport.config.viewportSelectors.push('my-custom-selector')`
15449
-
15450
15810
  \#\#\# Fixed elements obstructing the viewport
15451
15811
 
15452
15812
  Many applications have a navigation bar fixed to the top or bottom,
@@ -15454,14 +15814,16 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15454
15814
 
15455
15815
  You can make `up.reveal()` aware of these fixed elements
15456
15816
  so it can scroll the viewport far enough so the revealed element is fully visible.
15457
- To make `up.reveal()` aware fixed elements you can either:
15817
+ To make `up.reveal()` aware of fixed elements you can either:
15458
15818
 
15459
15819
  - give the element an attribute [`up-fixed="top"`](/up-fixed-top) or [`up-fixed="bottom"`](up-fixed-bottom)
15460
15820
  - [configure default options](/up.viewport.config) for `fixedTop` or `fixedBottom`
15461
15821
 
15462
15822
  @function up.reveal
15823
+
15463
15824
  @param {string|Element|jQuery} element
15464
15825
  The element to reveal.
15826
+
15465
15827
  @param {number} [options.scrollSpeed=1]
15466
15828
  The speed of the scrolling motion when scrolling with `{ behavior: 'smooth' }`.
15467
15829
 
@@ -15469,6 +15831,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15469
15831
  [native smooth scrolling](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior).
15470
15832
 
15471
15833
  Defaults to `up.viewport.config.scrollSpeed`.
15834
+
15472
15835
  @param {string} [options.revealSnap]
15473
15836
  When the the revealed element would be closer to the viewport's top edge
15474
15837
  than this value, Unpoly will scroll the viewport to the top.
@@ -15476,35 +15839,40 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15476
15839
  Set to `0` to disable snapping.
15477
15840
 
15478
15841
  Defaults to `up.viewport.config.revealSnap`.
15842
+
15479
15843
  @param {string|Element|jQuery} [options.viewport]
15480
15844
  The scrolling element to scroll.
15481
15845
 
15482
15846
  Defaults to the [given element's viewport](/up.viewport.closest).
15847
+
15483
15848
  @param {boolean} [options.top]
15484
15849
  Whether to scroll the viewport so that the first element row aligns
15485
15850
  with the top edge of the viewport.
15486
15851
 
15487
15852
  Defaults to `up.viewport.config.revealTop`.
15853
+
15488
15854
  @param {string}[options.behavior='auto']
15489
15855
  When set to `'auto'`, this will immediately scroll to the new position.
15490
15856
 
15491
15857
  When set to `'smooth'`, this will scroll smoothly to the new position.
15858
+
15492
15859
  @param {number}[options.speed]
15493
15860
  The speed of the scrolling motion when scrolling with `{ behavior: 'smooth' }`.
15494
15861
 
15495
15862
  Defaults to `up.viewport.config.scrollSpeed`.
15863
+
15496
15864
  @param {number} [options.padding]
15497
15865
  The desired padding between the revealed element and the
15498
15866
  closest [viewport](/up.viewport) edge (in pixels).
15499
15867
 
15500
15868
  Defaults to `up.viewport.config.revealPadding`.
15869
+
15501
15870
  @param {number|boolean} [options.snap]
15502
15871
  Whether to snap to the top of the viewport if the new scroll position
15503
15872
  after revealing the element is close to the top edge.
15504
15873
 
15505
15874
  Defaults to `up.viewport.config.revealSnap`.
15506
- @param {boolean} [options.peel=true]
15507
- Whether to close overlays obscuring the layer of `element`.
15875
+
15508
15876
  @return {Promise}
15509
15877
  A promise that fulfills when the element is revealed.
15510
15878
 
@@ -15513,13 +15881,12 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15513
15881
 
15514
15882
  When the scrolling is not animated, the promise will fulfill
15515
15883
  in the next [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/).
15884
+
15516
15885
  @stable
15517
15886
  */
15518
15887
  reveal = function(element, options) {
15519
15888
  var motion;
15520
- options = u.options(options, {
15521
- peel: true
15522
- });
15889
+ options = u.options(options);
15523
15890
  element = f.get(element, options);
15524
15891
  if (!(options.layer = up.layer.get(element))) {
15525
15892
  return up.error.failed.async('Cannot reveal a detached element');
@@ -15532,7 +15899,19 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15532
15899
  };
15533
15900
 
15534
15901
  /***
15535
- TODO: Docs
15902
+ Focuses the given element.
15903
+
15904
+ Focusing an element will also [reveal](/up.reveal) it, unless `{ preventScroll: true }` is passed.
15905
+
15906
+ @function up.focus
15907
+
15908
+ @param {string|Element|jQuery} element
15909
+ The element to focus.
15910
+
15911
+ @param {[options.preventScroll=false]}
15912
+ Whether to prevent changes to the acroll position.
15913
+
15914
+ @experimental
15536
15915
  */
15537
15916
  doFocus = function(element, options) {
15538
15917
  var oldScrollTop, viewport;
@@ -15557,13 +15936,6 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15557
15936
  doFocus(element, options);
15558
15937
  return element === document.activeElement;
15559
15938
  };
15560
- autofocus = function(element, options) {
15561
- var autofocusElement;
15562
- if (autofocusElement = e.subtree(element, '[autofocus]')[0]) {
15563
- doDocus(autofocusElement, options);
15564
- return true;
15565
- }
15566
- };
15567
15939
  isNativelyFocusable = function(element) {
15568
15940
  return e.matches(element, 'a[href], button, textarea, input, select');
15569
15941
  };
@@ -15633,6 +16005,9 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15633
16005
  Returns a list of all the viewports contained within the
15634
16006
  given selector or element.
15635
16007
 
16008
+ If the given element is itself a viewport, the element is included
16009
+ in the returned list.
16010
+
15636
16011
  @function up.viewport.subtree
15637
16012
  @param {string|Element|jQuery} target
15638
16013
  @param {Object} options
@@ -15825,30 +16200,11 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15825
16200
 
15826
16201
  The scroll positions will be associated with the current URL.
15827
16202
  They can later be restored by calling [`up.viewport.restoreScroll()`](/up.viewport.restoreScroll)
15828
- at the same URL, or by following a link with an [`[up-restore-scroll]`](/a-up-follow#up-restore-scroll)
16203
+ at the same URL, or by following a link with an [`[scroll="restore"]`](/a-up-follow#up-restore-scroll)
15829
16204
  attribute.
15830
16205
 
15831
- Unpoly automatically saves scroll positions before a [fragment update](/up.replace)
15832
- you will rarely need to call this function yourself.
15833
-
15834
- \#\#\# Examples
15835
-
15836
- Should you need to save the current scroll positions outside of a [fragment update](/up.replace),
15837
- you may call:
15838
-
15839
- up.viewport.saveScroll()
15840
-
15841
- Instead of saving the current scroll positions for the current URL, you may also pass another
15842
- url or vertical scroll positionsfor each viewport:
15843
-
15844
- up.viewport.saveScroll({
15845
- url: '/inbox',
15846
- tops: {
15847
- 'body': 0,
15848
- '.sidebar', 100,
15849
- '.main', 320
15850
- }
15851
- })
16206
+ Unpoly automatically saves scroll positions before [navigating](/navigation).
16207
+ You will rarely need to call this function yourself.
15852
16208
 
15853
16209
  @function up.viewport.saveScroll
15854
16210
  @param {string} [options.location]
@@ -16175,7 +16531,6 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
16175
16531
  absolutize: absolutize,
16176
16532
  focus: doFocus,
16177
16533
  tryFocus: tryFocus,
16178
- autofocus: autofocus,
16179
16534
  makeFocusable: makeFocusable
16180
16535
  });
16181
16536
  })();
@@ -16194,11 +16549,16 @@ Animation
16194
16549
 
16195
16550
  When you [update a page fragment](/up.link) you can animate the change.
16196
16551
 
16197
- Let's say you are using an [`up-follow`](/a-up-follow) link to update an element
16198
- with content from the server. You can add an attribute [`up-transition`](/a-up-follow#up-transition)
16199
- to smoothly fade out the old element while fading in the new element:
16552
+ You can add an attribute [`[up-transition]`](/a-up-transition) to your
16553
+ links or forms to smoothly fade out the old element while fading in the new element:
16200
16554
 
16201
- <a href="/users" up-target=".list" up-transition="cross-fade">Show users</a>
16555
+ ```html
16556
+ <a href="/users"
16557
+ up-target=".list"
16558
+ up-transition="cross-fade">
16559
+ Show users
16560
+ </a>
16561
+ ```
16202
16562
 
16203
16563
  \#\#\# Transitions vs. animations
16204
16564
 
@@ -16206,10 +16566,17 @@ When we morph between an old and a new element, we call it a *transition*.
16206
16566
  In contrast, when we animate a new element without simultaneously removing an
16207
16567
  old element, we call it an *animation*.
16208
16568
 
16209
- An example for an animation is opening a new dialog. We can animate the appearance
16210
- of the dialog by adding an [`[up-animation]`](/a-up-modal#up-animation) attribute to the opening link:
16569
+ An example for an animation is opening a new overlay. We can animate the appearance
16570
+ of the dialog by adding an [`[up-animation]`](/a-up-animation) attribute to the opening link:
16211
16571
 
16212
- <a href="/users" up-modal=".list" up-animation="move-from-top">Show users</a>
16572
+ ```html
16573
+ <a href="/users"
16574
+ up-target=".list"
16575
+ up-layer="new"
16576
+ up-animation="move-from-top">
16577
+ Show users
16578
+ </a>
16579
+ ```
16213
16580
 
16214
16581
  \#\#\# Which animations are available?
16215
16582
 
@@ -16219,12 +16586,16 @@ and [predefined animations](/up.animate#named-animations).
16219
16586
  You can define custom animations using `up.transition()` and
16220
16587
  `up.animation()`.
16221
16588
 
16589
+ @see a[up-transition]
16590
+ @see up.animation
16591
+ @see up.transition
16592
+
16222
16593
  @module up.motion
16223
16594
  */
16224
16595
 
16225
16596
  (function() {
16226
16597
  up.motion = (function() {
16227
- var animCount, animate, animateNow, applyConfig, composeTransitionFn, config, e, findAnimationFn, findNamedAnimation, findTransitionFn, finish, isEnabled, isNone, morph, motionController, namedAnimations, namedTransitions, pickDefault, registerAnimation, registerMoveMotions, registerOpacityAnimation, registerTransition, reset, skipAnimate, swapElementsDirectly, translateCSS, u, untranslatedBox, warnIfDisabled, willAnimate;
16598
+ var animate, animateNow, applyConfig, composeTransitionFn, config, e, findAnimationFn, findNamedAnimation, findTransitionFn, finish, isEnabled, isNone, morph, motionController, namedAnimations, namedTransitions, pickDefault, registerAnimation, registerMoveAnimations, registerOpacityAnimation, registerTransition, reset, skipAnimate, swapElementsDirectly, translateCSS, u, untranslatedBox, warnIfDisabled, willAnimate;
16228
16599
  u = up.util;
16229
16600
  e = up.element;
16230
16601
  namedAnimations = {};
@@ -16242,9 +16613,12 @@ You can define custom animations using `up.transition()` and
16242
16613
 
16243
16614
  See [W3C documentation](http://www.w3.org/TR/css3-transitions/#transition-timing-function)
16244
16615
  for a list of pre-defined timing functions.
16245
- @param {boolean} [config.enabled=true]
16616
+ @param {boolean} [config.enabled]
16246
16617
  Whether animation is enabled.
16247
16618
 
16619
+ By default animations are enabled, unless the user has configured their
16620
+ system to [minimize non-essential motion](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion).
16621
+
16248
16622
  Set this to `false` to disable animation globally.
16249
16623
  This can be useful in full-stack integration tests.
16250
16624
  @stable
@@ -16286,15 +16660,19 @@ You can define custom animations using `up.transition()` and
16286
16660
 
16287
16661
  \#\#\# Example
16288
16662
 
16289
- up.animate('.warning', 'fade-in')
16663
+ ```js
16664
+ up.animate('.warning', 'fade-in')
16665
+ ```
16290
16666
 
16291
16667
  You can pass additional options:
16292
16668
 
16293
- up.animate('.warning', 'fade-in', {
16294
- delay: 1000,
16295
- duration: 250,
16296
- easing: 'linear'
16297
- })
16669
+ ```
16670
+ up.animate('.warning', 'fade-in', {
16671
+ delay: 1000,
16672
+ duration: 250,
16673
+ easing: 'linear'
16674
+ })
16675
+ ```
16298
16676
 
16299
16677
  \#\#\# Named animations
16300
16678
 
@@ -16319,9 +16697,11 @@ You can define custom animations using `up.transition()` and
16319
16697
  By passing an object instead of an animation name, you can animate
16320
16698
  the CSS properties of the given element:
16321
16699
 
16322
- var warning = document.querySelector('.warning')
16323
- warning.style.opacity = 0
16324
- up.animate(warning, { opacity: 1 })
16700
+ ```
16701
+ var warning = document.querySelector('.warning')
16702
+ warning.style.opacity = 0
16703
+ up.animate(warning, { opacity: 1 })
16704
+ ```
16325
16705
 
16326
16706
  CSS properties must be given in `kebab-case`, not `camelCase`.
16327
16707
 
@@ -16357,7 +16737,6 @@ You can define custom animations using `up.transition()` and
16357
16737
  var animationFn, runNow, willRun;
16358
16738
  element = up.fragment.get(element);
16359
16739
  options = u.options(options);
16360
- applyConfig(options);
16361
16740
  animationFn = findAnimationFn(animation);
16362
16741
  willRun = willAnimate(element, animation, options);
16363
16742
  if (willRun) {
@@ -16370,6 +16749,7 @@ You can define custom animations using `up.transition()` and
16370
16749
  }
16371
16750
  };
16372
16751
  willAnimate = function(element, animationOrTransition, options) {
16752
+ applyConfig(options);
16373
16753
  return isEnabled() && !isNone(animationOrTransition) && options.duration > 0 && !e.isSingleton(element);
16374
16754
  };
16375
16755
  skipAnimate = function(element, animation) {
@@ -16378,7 +16758,6 @@ You can define custom animations using `up.transition()` and
16378
16758
  }
16379
16759
  return Promise.resolve();
16380
16760
  };
16381
- animCount = 0;
16382
16761
 
16383
16762
  /***
16384
16763
  Animates the given element's CSS properties using CSS transitions.
@@ -16428,7 +16807,7 @@ You can define custom animations using `up.transition()` and
16428
16807
  Animations are completed by jumping to the last animation frame instantly.
16429
16808
  Promises returned by animation and transition functions instantly settle.
16430
16809
 
16431
- Emits the `up:motion:finish` event that is already handled by `up.animate()`.
16810
+ Emits the `up:motion:finish` event that is handled by `up.animate()`.
16432
16811
 
16433
16812
  Does nothing if there are no animation to complete.
16434
16813
 
@@ -16552,7 +16931,7 @@ You can define custom animations using `up.transition()` and
16552
16931
  });
16553
16932
  trackable = function() {
16554
16933
  var promise;
16555
- promise = scrollNew();
16934
+ promise = Promise.resolve(scrollNew());
16556
16935
  promise = promise.then(function() {
16557
16936
  var scrollTopAfterReveal;
16558
16937
  scrollTopAfterReveal = viewport.scrollTop;
@@ -16626,18 +17005,20 @@ You can define custom animations using `up.transition()` and
16626
17005
  });
16627
17006
 
16628
17007
  /***
16629
- Defines a named transition that [morphs](/up.element) from one element to another.
17008
+ Defines a named transition that [morphs](/up.morph) from one element to another.
16630
17009
 
16631
17010
  \#\#\# Example
16632
17011
 
16633
17012
  Here is the definition of the pre-defined `cross-fade` animation:
16634
17013
 
16635
- up.transition('cross-fade', (oldElement, newElement, options) ->
16636
- Promise.all([
16637
- up.animate(oldElement, 'fade-out', options),
16638
- up.animate(newElement, 'fade-in', options)
16639
- ])
16640
- )
17014
+ ```js
17015
+ up.transition('cross-fade', (oldElement, newElement, options) ->
17016
+ Promise.all([
17017
+ up.animate(oldElement, 'fade-out', options),
17018
+ up.animate(newElement, 'fade-in', options)
17019
+ ])
17020
+ )
17021
+ ```
16641
17022
 
16642
17023
  It is recommended that your transitions use [`up.animate()`](/up.animate),
16643
17024
  passing along the `options` that were passed to you.
@@ -16672,10 +17053,12 @@ You can define custom animations using `up.transition()` and
16672
17053
 
16673
17054
  Here is the definition of the pre-defined `fade-in` animation:
16674
17055
 
16675
- up.animation('fade-in', function(element, options) {
16676
- element.style.opacity = 0
16677
- up.animate(element, { opacity: 1 }, options)
16678
- })
17056
+ ```js
17057
+ up.animation('fade-in', function(element, options) {
17058
+ element.style.opacity = 0
17059
+ up.animate(element, { opacity: 1 }, options)
17060
+ })
17061
+ ```
16679
17062
 
16680
17063
  It is recommended that your definitions always end by calling
16681
17064
  calling [`up.animate()`](/up.animate) with an object argument, passing along
@@ -16684,7 +17067,7 @@ You can define custom animations using `up.transition()` and
16684
17067
  If you choose to *not* use `up.animate()` and roll your own
16685
17068
  animation code instead, your code must honor the following contract:
16686
17069
 
16687
- 1. It must honor the options `{ duration, easing }` if given
17070
+ 1. It must honor the options `{ duration, easing }`, if given.
16688
17071
  2. It must *not* remove any of the given elements from the DOM.
16689
17072
  3. It returns a promise that is fulfilled when the transition has ended
16690
17073
  4. If during the animation an event `up:motion:finish` is emitted on
@@ -16743,7 +17126,7 @@ You can define custom animations using `up.transition()` and
16743
17126
  e.setStyle(element, translateCSS(0, 0));
16744
17127
  return element.getBoundingClientRect();
16745
17128
  };
16746
- registerMoveMotions = function(direction, boxToTransform) {
17129
+ registerMoveAnimations = function(direction, boxToTransform) {
16747
17130
  var animationFromName, animationToName;
16748
17131
  animationToName = "move-to-" + direction;
16749
17132
  animationFromName = "move-from-" + direction;
@@ -16761,22 +17144,22 @@ You can define custom animations using `up.transition()` and
16761
17144
  return animateNow(element, translateCSS(0, 0), options);
16762
17145
  });
16763
17146
  };
16764
- registerMoveMotions('top', function(box) {
17147
+ registerMoveAnimations('top', function(box) {
16765
17148
  var travelDistance;
16766
17149
  travelDistance = box.top + box.height;
16767
17150
  return translateCSS(0, -travelDistance);
16768
17151
  });
16769
- registerMoveMotions('bottom', function(box) {
17152
+ registerMoveAnimations('bottom', function(box) {
16770
17153
  var travelDistance;
16771
17154
  travelDistance = up.viewport.rootHeight() - box.top;
16772
17155
  return translateCSS(0, travelDistance);
16773
17156
  });
16774
- registerMoveMotions('left', function(box) {
17157
+ registerMoveAnimations('left', function(box) {
16775
17158
  var travelDistance;
16776
17159
  travelDistance = box.left + box.width;
16777
17160
  return translateCSS(-travelDistance, 0);
16778
17161
  });
16779
- registerMoveMotions('right', function(box) {
17162
+ registerMoveAnimations('right', function(box) {
16780
17163
  var travelDistance;
16781
17164
  travelDistance = up.viewport.rootWidth() - box.left;
16782
17165
  return translateCSS(travelDistance, 0);
@@ -16791,10 +17174,17 @@ You can define custom animations using `up.transition()` and
16791
17174
  [Follows](/a-up-follow) this link and swaps in the new fragment
16792
17175
  with an animated transition.
16793
17176
 
17177
+ Note that transitions are not possible when replacing the `body`
17178
+ element.
17179
+
16794
17180
  \#\#\# Example
16795
17181
 
16796
17182
  ```html
16797
- <a href="/page2" up-transition="move-left">Next page</a>
17183
+ <a href="/page2"
17184
+ up-target=".story"
17185
+ up-transition="move-left">
17186
+ Next page
17187
+ </a>
16798
17188
  ```
16799
17189
 
16800
17190
  @selector a[up-transition]
@@ -16806,6 +17196,7 @@ You can define custom animations using `up.transition()` and
16806
17196
  The transition to use when the server responds with an error code.
16807
17197
 
16808
17198
  @see server-errors
17199
+ @stable
16809
17200
  */
16810
17201
 
16811
17202
  /***
@@ -16815,7 +17206,9 @@ You can define custom animations using `up.transition()` and
16815
17206
  \#\#\# Example
16816
17207
 
16817
17208
  ```html
16818
- <form action="/tasks" up-transition="cross-fade">
17209
+ <form action="/tasks"
17210
+ up-target=".content"
17211
+ up-transition="cross-fade">
16819
17212
  ...
16820
17213
  </form>
16821
17214
  ```
@@ -16829,6 +17222,7 @@ You can define custom animations using `up.transition()` and
16829
17222
  The transition to use when the server responds with an error code.
16830
17223
 
16831
17224
  @see server-errors
17225
+ @stable
16832
17226
  */
16833
17227
  up.on('up:framework:boot', warnIfDisabled);
16834
17228
  up.on('up:framework:reset', reset);
@@ -16869,43 +17263,25 @@ You can define custom animations using `up.transition()` and
16869
17263
  Network requests
16870
17264
  ================
16871
17265
 
16872
- TODO: Rewrite this page
17266
+ Unpoly ships with an optimized HTTP client for fast and effective
17267
+ communication with your server-side app.
16873
17268
 
16874
- Unpoly comes with a number of tricks to shorten the latency between browser and server.
17269
+ While you can use the browser's native `fetch()` function,
17270
+ Unpoly's `up.request()` has a number of convenience features:
16875
17271
 
16876
- \#\#\# Server responses are cached by default
17272
+ - Requests may be [cached](/up.request#options.cache) to reuse responses and enable [preloading](/a-up-preload).
17273
+ - Requests send [additional HTTP headers](/up.protocol) that the server may use to optimize its response.
17274
+ For example, when updating a [fragment](/up.fragment), the fragment's selector is automatically sent
17275
+ as an `X-Up-Target` header. The server may choose to only render the targeted fragment.
17276
+ - Useful events like `up:request:loaded` or `up:request:late` are emitted throughout the request/response
17277
+ lifecycle.
17278
+ - When too many requests are sent concurrently, excessive requests are [queued](/up.network.config#config.concurrency).
17279
+ This prevents exhausting the user's bandwidth and limits race conditions in end-to-end tests.
17280
+ - A very concise API requiring zero boilerplate code.
16877
17281
 
16878
- Unpoly caches server responses for a few minutes,
16879
- making requests to these URLs return instantly.
16880
- All Unpoly functions and selectors go through this cache, unless
16881
- you explicitly pass a `{ cache: false }` option or set an `up-cache="false"` attribute.
16882
-
16883
- The cache holds up to 50 responses for 5 minutes. You can configure the cache size and expiry using
16884
- [`up.network.config`](/up.network.config), or clear the cache manually using [`up.cache.clear()`](/up.cache.clear).
16885
-
16886
- Also the entire cache is cleared with every non-`GET` request (like `POST` or `PUT`).
16887
-
16888
- If you need to make cache-aware requests from your [custom JavaScript](/up.syntax),
16889
- use [`up.request()`](/up.request).
16890
-
16891
- \#\#\# Preloading links
16892
-
16893
- Unpoly also lets you speed up reaction times by [preloading
16894
- links](/a-up-preload) when the user hovers over the click area (or puts the mouse/finger
16895
- down). This way the response will already be cached when
16896
- the user releases the mouse/finger.
16897
-
16898
- \#\#\# Spinners
16899
-
16900
- You can listen to the [`up:request:late`](/up:request:late) event to implement a spinner
16901
- that appears during a long-running request.
16902
-
16903
- \#\#\# More acceleration
16904
-
16905
- Other Unpoly modules contain even more tricks to outsmart network latency:
16906
-
16907
- - [Instantaneous feedback for links that are currently loading](/a.up-active)
16908
- - [Follow links on `mousedown` instead of `click`](/a-up-instant)
17282
+ @see up.request
17283
+ @see up.Response
17284
+ @see up:request:late
16909
17285
 
16910
17286
  @module up.network
16911
17287
  */
@@ -16923,8 +17299,8 @@ You can define custom animations using `up.transition()` and
16923
17299
  Additional requests are queued. [Preload](/a-up-preload) requests are
16924
17300
  always queued behind non-preload requests.
16925
17301
 
16926
- You might find it useful to set the request concurrency `1` in full-stack
16927
- integration tests (e.g. Selenium) to prevent race conditions.
17302
+ You might find it useful to set the request concurrency `1` in end-to-end tests
17303
+ to prevent race conditions.
16928
17304
 
16929
17305
  Note that your browser might [impose its own request limit](http://www.browserscope.org/?category=network)
16930
17306
  regardless of what you configure here.
@@ -17026,7 +17402,7 @@ You can define custom animations using `up.transition()` and
17026
17402
 
17027
17403
  @stable
17028
17404
  */
17029
- var abortRequests, cache, config, handleCaching, isBusy, isIdle, isSafeMethod, makeRequest, mimicLocalRequest, parseRequestOptions, preload, queue, queueRequest, registerAliasForRedirect, reset, shouldReduceRequests, useCachedRequest;
17405
+ var abortRequests, cache, config, handleCaching, isBusy, isIdle, isSafeMethod, makeRequest, mimicLocalRequest, parseRequestOptions, queue, queueRequest, registerAliasForRedirect, reset, shouldReduceRequests, useCachedRequest;
17030
17406
  config = new up.Config(function() {
17031
17407
  return {
17032
17408
  concurrency: 4,
@@ -17084,13 +17460,24 @@ You can define custom animations using `up.transition()` and
17084
17460
  /***
17085
17461
  Removes all [cache](/up.cache.get) entries.
17086
17462
 
17087
- Unpoly also automatically clears the cache whenever it processes
17088
- a request with an [unsafe](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1)
17089
- HTTP method like `POST`.
17463
+ To only remove some cache entries, pass a [URL pattern](/url-patterns):
17464
+
17465
+ ```js
17466
+ up.cache.clear('/users/*')
17467
+ ```
17468
+
17469
+ \#\#\# Other reasons the cache may clear
17470
+
17471
+ By default Unpoly automatically clears the entire cache whenever it processes
17472
+ a request with an non-GET HTTP method. To customize this rule, use `up.network.config.clearCache`.
17090
17473
 
17091
17474
  The server may also clear the cache by sending an [`X-Up-Cache: clear`](/X-Up-Cache) header.
17092
17475
 
17093
17476
  @function up.cache.clear
17477
+ @param {string} [pattern]
17478
+ A [URL pattern](/url-patterns) matching cache entries that should be cleared.
17479
+
17480
+ If omitted, the entire cache is cleared.
17094
17481
  @stable
17095
17482
  */
17096
17483
 
@@ -17148,39 +17535,45 @@ You can define custom animations using `up.transition()` and
17148
17535
  Makes an AJAX request to the given URL.
17149
17536
 
17150
17537
  Returns an `up.Request` object which contains information about the request.
17151
- The request object is also a promise for its `up.Response`.
17538
+ This request object is also a promise for an `up.Response` that contains
17539
+ the response text, headers, etc.
17152
17540
 
17153
17541
  \#\#\# Example
17154
17542
 
17155
- let request = up.request('/search', { params: { query: 'sunshine' } })
17156
- console.log('We made a request to', request.url)
17543
+ ```js
17544
+ let request = up.request('/search', { params: { query: 'sunshine' } })
17545
+ console.log('We made a request to', request.url)
17157
17546
 
17158
- let response = await request
17159
- console.log('The response text is', response.text)
17547
+ let response = await request
17548
+ console.log('The response text is', response.text)
17549
+ ```
17160
17550
 
17161
17551
  \#\#\# Error handling
17162
17552
 
17163
17553
  The returned promise will fulfill with an `up.Response` when the server
17164
17554
  responds with an HTTP status of 2xx (like `200`).
17165
17555
 
17166
- When the server responds with an error code (like `422` or `500`), the promise
17556
+ When the server responds with an HTTP error code (like `422` or `500`), the promise
17167
17557
  will *reject* with `up.Response`.
17168
17558
 
17169
17559
  When the request fails from a fatal error (like a timeout or loss of connectivity),
17170
17560
  the promise will reject with an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object.
17171
17561
 
17172
- Here is an example for a complete control flow that also handles errors:
17562
+ Here is an example for a complete control flow that handles both HTTP error codes
17563
+ and fatal errors:
17173
17564
 
17174
- try {
17175
- let response = await up.request('/search', { params: { query: 'sunshine' } })
17176
- console.log('Successful response with text:', response.text)
17177
- } catch (e) {
17178
- if (e instanceof up.Response) {
17179
- console.log('Server responded with HTTP status %s and text %s', e.status, e.text)
17180
- } else {
17181
- console.log('Fatal error during request:', e.message)
17182
- }
17183
- }
17565
+ ```js
17566
+ try {
17567
+ let response = await up.request('/search', { params: { query: 'sunshine' } })
17568
+ console.log('Successful response with text:', response.text)
17569
+ } catch (e) {
17570
+ if (e instanceof up.Response) {
17571
+ console.log('Server responded with HTTP status %s and text %s', e.status, e.text)
17572
+ } else {
17573
+ console.log('Fatal error during request:', e.message)
17574
+ }
17575
+ }
17576
+ ```
17184
17577
 
17185
17578
  \#\#\# Caching
17186
17579
 
@@ -17223,10 +17616,13 @@ You can define custom animations using `up.transition()` and
17223
17616
 
17224
17617
  With `{ cache: false }` (the default) Unpoly will always make a network request.
17225
17618
 
17226
- @param {boolean} [options.clearCache]
17227
- Whether to clear the cache after this request.
17619
+ @param {boolean|string} [options.clearCache]
17620
+ Whether to [clear](/up.cache.clear) the [cache](/up.cache.get) after this request.
17621
+
17622
+ You may also pass a [URL pattern](/url-patterns) to only clear matching requests.
17228
17623
 
17229
- Defaults to the result of `up.network.config.clearCache`.
17624
+ Defaults to the result of `up.network.config.clearCache`, which
17625
+ defaults to clearing the entire cache after a non-GET request.
17230
17626
 
17231
17627
  @param {Object} [options.headers={}]
17232
17628
  An object of additional HTTP headers.
@@ -17251,13 +17647,13 @@ You can define custom animations using `up.transition()` and
17251
17647
  @param {string} [options.target='body']
17252
17648
  The CSS selector that will be sent as an `X-Up-Target` header.
17253
17649
 
17254
- @param {string} [options.layer='current']
17255
- The [layer](/up.layer) this request is associated with.
17256
-
17257
17650
  @param {string} [options.failTarget='body']
17258
17651
  The CSS selector that will be sent as an `X-Up-Fail-Target` header.
17259
17652
 
17260
17653
  @param {string} [options.layer='current']
17654
+ The [layer](/up.layer) this request is associated with.
17655
+
17656
+ @param {string} [options.failLayer='current']
17261
17657
  The [layer](/up.layer) this request is associated with if the server [sends a HTTP status code](/server-errors).
17262
17658
 
17263
17659
  @param {Element} [options.origin]
@@ -17309,16 +17705,6 @@ You can define custom animations using `up.transition()` and
17309
17705
  return cache.clear(clearCache);
17310
17706
  }
17311
17707
  };
17312
- preload = function() {
17313
- var args, base, options;
17314
- args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
17315
- if (typeof (base = up.migrate).handleNetworkPreloadArgs === "function") {
17316
- base.handleNetworkPreloadArgs.apply(base, args);
17317
- }
17318
- options = parseRequestOptions(args);
17319
- options.preload = true;
17320
- return makeRequest(options);
17321
- };
17322
17708
  parseRequestOptions = function(args) {
17323
17709
  var base, options;
17324
17710
  options = u.extractOptions(args);
@@ -17430,18 +17816,24 @@ You can define custom animations using `up.transition()` and
17430
17816
 
17431
17817
  Without arguments, this will abort all pending requests:
17432
17818
 
17433
- up.network.abort()
17819
+ ```js
17820
+ up.network.abort()
17821
+ ```
17434
17822
 
17435
17823
  To abort a given `up.Request` object, pass it as the first argument:
17436
17824
 
17437
- let request = up.request('/path')
17438
- up.network.abort(request)
17825
+ ```js
17826
+ let request = up.request('/path')
17827
+ up.network.abort(request)
17828
+ ```
17439
17829
 
17440
17830
  To abort all requests matching a condition, pass a function that takes a request
17441
17831
  and returns a boolean value. Unpoly will abort all request for which the given
17442
17832
  function returns `true`. E.g. to abort all requests with a HTTP method as `GET`:
17443
17833
 
17444
- up.network.abort((request) => request.method == 'GET')
17834
+ ```js
17835
+ up.network.abort((request) => request.method == 'GET')
17836
+ ```
17445
17837
 
17446
17838
  @function up.network.abort
17447
17839
  @param {up.Request|boolean|Function(up.Request): boolean} [matcher=true]
@@ -17603,7 +17995,6 @@ You can define custom animations using `up.transition()` and
17603
17995
  up.on('up:framework:reset', reset);
17604
17996
  return {
17605
17997
  request: makeRequest,
17606
- preload: preload,
17607
17998
  cache: cache,
17608
17999
  isIdle: isIdle,
17609
18000
  isBusy: isBusy,
@@ -17635,15 +18026,30 @@ You can define custom animations using `up.transition()` and
17635
18026
  Layers
17636
18027
  ======
17637
18028
 
17638
- TODO
18029
+ Unpoly allows you to [open page fragments in an overlay](/opening-overlays). Overlays may be stacked infinitely.
18030
+
18031
+ A variety of [overlay modes](/layer-terminology) are supported,
18032
+ such as modal dialogs, popup overlays or drawers. You may [customize their appearance and behavior](/customizing-overlays).
18033
+
18034
+ Layers are isolated, meaning a screen in one layer will not accidentally see elements
18035
+ or events from another layer. For instance, [fragment links](/up.link) will only update elements from the [current layer](/up.layer.current)
18036
+ unless you [explicitly target another layer](/layer-option).
18037
+
18038
+ Overlays allow you to break up a complex screen into [subinteractions](/subinteractions).
18039
+ Subinteractions take place in overlays and may span one or many pages. The original screen remains open in the background.
18040
+ Once the subinteraction is *done*, the overlay is closed and a result value is communicated back to the parent layer.
18041
+
18042
+ @see a[up-layer=new]
18043
+ @see up.layer.current
18044
+ @see up.layer.on
18045
+ @see up.layer.ask
17639
18046
 
17640
18047
  @module up.layer
17641
18048
  */
17642
18049
 
17643
18050
  up.layer = (function() {
17644
- var LAYER_CLASSES, OVERLAY_CLASSES, OVERLAY_MODES, anySelector, api, ask, build, closeCallbackAttr, config, handlers, isOverlayMode, mainTargets, modeConfigs, normalizeOptions, open, openCallbackAttr, optionToString, reset, stack;
18051
+ var LAYER_CLASSES, OVERLAY_CLASSES, anySelector, api, ask, build, closeCallbackAttr, config, handlers, mainTargets, modeConfigs, normalizeOptions, open, openCallbackAttr, optionToString, reset, stack;
17645
18052
  OVERLAY_CLASSES = [up.Layer.Modal, up.Layer.Popup, up.Layer.Drawer, up.Layer.Cover];
17646
- OVERLAY_MODES = u.map(OVERLAY_CLASSES, 'mode');
17647
18053
  LAYER_CLASSES = [up.Layer.Root].concat(OVERLAY_CLASSES);
17648
18054
 
17649
18055
  /***
@@ -17682,7 +18088,7 @@ You can define custom animations using `up.transition()` and
17682
18088
  up.layer.config.modal.openAnimation = 'move-from-top'
17683
18089
  ```
17684
18090
 
17685
- To configure an additional [main target](/main)
18091
+ To configure an additional [main target](/up-main)
17686
18092
  for overlay of any mode:
17687
18093
 
17688
18094
  ```js
@@ -17841,16 +18247,17 @@ You can define custom animations using `up.transition()` and
17841
18247
  });
17842
18248
 
17843
18249
  /***
17844
- TODO: Docs
18250
+ A list of layers that are currently open.
18251
+
18252
+ The first element in the list is the [root layer](/up.layer.root).
18253
+ The last element is the [frontmost layer](/up.layer.front).
17845
18254
 
17846
- @function up.layer.stack
18255
+ @property up.layer.stack
18256
+ @param {List<up.Layer>} stack
17847
18257
  @stable
17848
18258
  */
17849
18259
  stack = null;
17850
18260
  handlers = [];
17851
- isOverlayMode = function(mode) {
17852
- return u.contains(OVERLAY_MODES, mode);
17853
- };
17854
18261
  mainTargets = function(mode) {
17855
18262
  return u.flatMap(modeConfigs(mode), 'mainTargets');
17856
18263
  };
@@ -17974,7 +18381,7 @@ You can define custom animations using `up.transition()` and
17974
18381
  How the overlay may be [dismissed](/closing-overlays) by the user.
17975
18382
 
17976
18383
  Supported values are `'key'`, `'outside'` and `'button'`.
17977
- See [user dismiss controls](/closing-overlays#user-facing-dismiss-controls)
18384
+ See [customizing dismiss controls](/closing-overlays#customizing-dismiss-controls)
17978
18385
  for details.
17979
18386
 
17980
18387
  You may enable multiple dismiss controls by passing an array or
@@ -17988,7 +18395,7 @@ You can define custom animations using `up.transition()` and
17988
18395
  If set to `true` the overlay location and title will be shown in browser UI.
17989
18396
 
17990
18397
  If set to `'auto'` history will be visible if the initial overlay
17991
- content matches a [main target](/main).
18398
+ content matches a [main target](/up-main).
17992
18399
 
17993
18400
  @param {string|Function} [options.animation]
17994
18401
  The opening animation.
@@ -18087,22 +18494,61 @@ You can define custom animations using `up.transition()` and
18087
18494
  };
18088
18495
 
18089
18496
  /***
18090
- TODO: Docs
18091
- TODO: Document that listeners may manipulate options
18092
- TODO: Document that it's emitted on the document
18497
+ This event is emitted before an overlay is opened.
18498
+
18499
+ The overlay is not yet part of the [layer stack](/up.layer.stack) and has not yet been placed
18500
+ in the DOM. Listeners may prevent this event to prevent the overlay from opening.
18501
+
18502
+ The event is emitted on the `document`.
18503
+
18504
+ \#\#\# Changing layer options
18505
+
18506
+ Listeners may inspect and manipulate options for the overlay that is about to open.
18507
+
18508
+ For example, to give overlays the CSS class `.warning` if the initial URL contains
18509
+ the word `"confirm"`:
18510
+
18511
+ ```js
18512
+ up.on('up:layer:open', function(event) {
18513
+ if (event.layerOptions.url.includes('confirm')) {
18514
+ event.layerOptions.class = 'warning'
18515
+ }
18516
+ })
18517
+ ```
18093
18518
 
18094
18519
  @event up:layer:open
18095
18520
  @param {Object} event.layerOptions
18521
+ Options for the overlay that is about to open.
18522
+
18523
+ Listeners may inspect and change the options.
18524
+ All options for `up.layer.open()` may be used.
18096
18525
  @param {Element} event.origin
18526
+ The link element that is opening the overlay.
18527
+ @param event.preventDefault()
18528
+ Event listeners may call this method to prevent the overlay from opening.
18097
18529
  @stable
18098
18530
  */
18099
18531
 
18100
18532
  /***
18101
- TODO: Docs
18533
+ This event is emitted after a new overlay has been placed into the DOM.
18534
+
18535
+ The event is emitted right before the opening animation starts. Because the overlay
18536
+ has not been rendered by the browser, this makes it a good occasion to
18537
+ [customize overlay elements](/customizing-overlays#customizing-overlay-elements):
18538
+
18539
+ ```js
18540
+ up.on('up:layer:opened', function(event) {
18541
+ if (isChristmas()) {
18542
+ up.element.affix(event.layer.element, '.santa-hat', text: 'Merry Christmas!')
18543
+ }
18544
+ })
18545
+ ```
18102
18546
 
18103
18547
  @event up:layer:opened
18104
18548
  @param {Element} event.origin
18549
+ The link element that is opening the overlay.
18105
18550
  @param {up.Layer} event.layer
18551
+ The [layer object](/up.Layer) that is opening.
18106
18552
  @stable
18107
18553
  */
18108
18554
 
@@ -18110,7 +18556,7 @@ You can define custom animations using `up.transition()` and
18110
18556
  This event is emitted after a layer's [location property](/up.Layer.prototype.location)
18111
18557
  has changed value.
18112
18558
 
18113
- This event is also emitted when a layer [without history](/up.Layer.prototype.historyVisible)
18559
+ This event is also emitted when a layer [without visible history](/up.Layer.prototype.historyVisible)
18114
18560
  has reached a new location.
18115
18561
 
18116
18562
  @param {string} event.location
@@ -18146,6 +18592,7 @@ You can define custom animations using `up.transition()` and
18146
18592
  A promise that will settle when the overlay closes.
18147
18593
 
18148
18594
  When the overlay was accepted, the promise will fulfill with the overlay's acceptance value.
18595
+
18149
18596
  When the overlay was dismissed, the promise will reject with the overlay's dismissal value.
18150
18597
 
18151
18598
  @stable
@@ -18177,7 +18624,7 @@ You can define custom animations using `up.transition()` and
18177
18624
  };
18178
18625
 
18179
18626
  /***
18180
- [Follows](/a-up-follow) this link and opens the result in a new layer.
18627
+ [Follows](/a-up-follow) this link and opens the result in a new overlay.
18181
18628
 
18182
18629
  \#\#\# Example
18183
18630
 
@@ -18218,12 +18665,12 @@ You can define custom animations using `up.transition()` and
18218
18665
  If set to `true` the overlay location and title will be shown in browser UI.
18219
18666
 
18220
18667
  If set to `'auto'` history will be visible if the initial overlay
18221
- content matches a [main target](/main).
18668
+ content matches a [main target](/up-main).
18222
18669
 
18223
18670
  @param [up-dismissable]
18224
18671
  How the overlay may be [dismissed](/closing-overlays) by the user.
18225
18672
 
18226
- See [user dismiss controls](/closing-overlays#user-facing-dismiss-controls)
18673
+ See [customizing dismiss controls](/closing-overlays#customizing-dismiss-controls)
18227
18674
  for details.
18228
18675
 
18229
18676
  You may enable multiple dismiss controls by passing a space-separated string.
@@ -18421,12 +18868,33 @@ You can define custom animations using `up.transition()` and
18421
18868
  The *current* layer is usually the [frontmost layer](/up.layer.front).
18422
18869
  There are however some cases where the current layer is a layer in the background:
18423
18870
 
18424
- - While an element in a background layer is [compiled](/up.compiler).
18871
+ - While an element in a background layer is being [compiled](/up.compiler).
18425
18872
  - While an Unpoly event like `up:request:loaded` is being triggered from a background layer.
18426
- - While a running event listener was bound to a background layer using `up.Layer#on()`.
18873
+ - While an event listener bound to a background layer using `up.Layer#on()` is being called.
18427
18874
 
18428
18875
  To temporarily change the current layer from your own code, use `up.Layer#asCurrent()`.
18429
18876
 
18877
+ \#\#\# Remembering the current layer
18878
+
18879
+ Most functions in the `up.layer` package affect the current layer. E.g. `up.layer.dismiss()`
18880
+ is shorthand for `up.layer.current.dismiss()`.
18881
+
18882
+ As described above `up.layer.current` is set to the right layer in compilers and most events,
18883
+ even if that layer is not the frontmost layer.
18884
+
18885
+ If you have async code, the current layer may change when your callback is called.
18886
+ To address this you may retrieve the current layer for later reference:
18887
+
18888
+ ```js
18889
+ function dismissCurrentLayerIn(seconds) {
18890
+ let savedLayer = up.layer.current // returns an up.Layer object
18891
+ let dismiss = () => savedLayer.dismiss()
18892
+ setTimeout(dismiss, seconds * 1000)
18893
+ }
18894
+
18895
+ dismissCurrentLayerIn(10) //
18896
+ ```
18897
+
18430
18898
  @property up.layer.current
18431
18899
  @param {up.Layer} current
18432
18900
  @stable
@@ -18470,6 +18938,9 @@ You can define custom animations using `up.transition()` and
18470
18938
  /***
18471
18939
  Returns the [root layer](/layer-terminology).
18472
18940
 
18941
+ The root layer represents the initial page before any overlay was [opened](/opening-overlays).
18942
+ The root layer always exists and cannot be closed.
18943
+
18473
18944
  @property up.layer.root
18474
18945
  @param {up.Layer} root
18475
18946
  @stable
@@ -18480,7 +18951,10 @@ You can define custom animations using `up.transition()` and
18480
18951
 
18481
18952
  If no overlay is open, an empty array is returned.
18482
18953
 
18483
- @function up.layer.overlays
18954
+ To get an array of *all* layers including the [root layer](/up.layer.root),
18955
+ use `up.layer.stack`.
18956
+
18957
+ @property up.layer.overlays
18484
18958
  @param {Array<up.Layer>} overlays
18485
18959
  @stable
18486
18960
  */
@@ -18505,9 +18979,9 @@ You can define custom animations using `up.transition()` and
18505
18979
  Afterwards the only remaining layer will be the [root layer](/up.layer.root).
18506
18980
 
18507
18981
  @function up.layer.dismissOverlays
18508
- @param {any} value
18982
+ @param {any} [value]
18509
18983
  The dismissal value.
18510
- @param {Object} options
18984
+ @param {Object} [options]
18511
18985
  See options for `up.layer.dismiss()`.
18512
18986
  @stable
18513
18987
  */
@@ -18518,13 +18992,13 @@ You can define custom animations using `up.transition()` and
18518
18992
  /***
18519
18993
  [Accepts](/closing-overlays) the [current layer](up.layer.current).
18520
18994
 
18521
- This is a shortcut for `up.layer.current.dismiss()`.
18522
- See `up.Layer#dismiss()` for more documentation.
18995
+ This is a shortcut for `up.layer.current.accept()`.
18996
+ See `up.Layer#accept()` for more documentation.
18523
18997
 
18524
- @function up.layer.dismiss
18998
+ @function up.layer.accept
18525
18999
  @param {any} [value]
18526
19000
  @param {Object} [options]
18527
- @return
19001
+ @stable
18528
19002
  */
18529
19003
 
18530
19004
  /***
@@ -18536,7 +19010,7 @@ You can define custom animations using `up.transition()` and
18536
19010
  @function up.layer.dismiss
18537
19011
  @param {any} [value]
18538
19012
  @param {Object} [options]
18539
- @return
19013
+ @stable
18540
19014
  */
18541
19015
 
18542
19016
  /***
@@ -18545,7 +19019,7 @@ You can define custom animations using `up.transition()` and
18545
19019
  This is a shortcut for `up.layer.current.isRoot()`.
18546
19020
  See `up.Layer#isRoot()` for more documentation..
18547
19021
 
18548
- @function up.layer.isFront
19022
+ @function up.layer.isRoot
18549
19023
  @return {boolean}
18550
19024
  @stable
18551
19025
  */
@@ -18573,7 +19047,7 @@ You can define custom animations using `up.transition()` and
18573
19047
  */
18574
19048
 
18575
19049
  /***
18576
- Listens to a ([DOM event](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events)
19050
+ Listens to a [DOM event](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events)
18577
19051
  that originated on an element [contained](/up.Layer.prototype.contains) by the [current layer](/up.layer.current).
18578
19052
 
18579
19053
  This is a shortcut for `up.layer.current.on()`.
@@ -18582,7 +19056,7 @@ You can define custom animations using `up.transition()` and
18582
19056
  @function up.layer.on
18583
19057
  @param {string} types
18584
19058
  A space-separated list of event types to bind to.
18585
- @param {string} [selector]
19059
+ @param {string|Function(): string} [selector]
18586
19060
  The selector of an element on which the event must be triggered.
18587
19061
  @param {Object} [options]
18588
19062
  @param {Function(event, [element], [data])} listener
@@ -18599,9 +19073,8 @@ You can define custom animations using `up.transition()` and
18599
19073
  See `up.Layer#off()` for more documentation.
18600
19074
 
18601
19075
  @function up.layer.off
18602
- @param {Element|jQuery} [element=document]
18603
19076
  @param {string} events
18604
- @param {string} [selector]
19077
+ @param {string|Function(): string} [selector]
18605
19078
  @param {Function(event, [element], [data])} listener
18606
19079
  The listener function to unbind.
18607
19080
  @stable
@@ -18614,7 +19087,6 @@ You can define custom animations using `up.transition()` and
18614
19087
  See `up.Layer#emit()` for more documentation.
18615
19088
 
18616
19089
  @function up.layer.emit
18617
- @param {Element|jQuery} [target=up.layer.element]
18618
19090
  @param {string} eventType
18619
19091
  @param {Object} [props={}]
18620
19092
  @stable
@@ -18644,7 +19116,7 @@ You can define custom animations using `up.transition()` and
18644
19116
  */
18645
19117
 
18646
19118
  /***
18647
- The location of the [current layer](/up.layer.current).
19119
+ The location URL of the [current layer](/up.layer.current).
18648
19120
 
18649
19121
  This is a shortcut for `up.layer.current.location`.
18650
19122
  See `up.Layer#location` for more documentation.
@@ -18653,23 +19125,34 @@ You can define custom animations using `up.transition()` and
18653
19125
  @param {string} location
18654
19126
  @stable
18655
19127
  */
19128
+
19129
+ /***
19130
+ The [current layer](/up.layer.current)'s [mode](/up.layer.mode)
19131
+ which governs its appearance and behavior.
19132
+
19133
+ @property up.layer.mode
19134
+ @param {string} mode
19135
+ @stable
19136
+ */
19137
+
19138
+ /***
19139
+ The [context](/context) of the [current layer](/up.layer.current).
19140
+
19141
+ This is aliased as `up.context`.
19142
+
19143
+ @property up.layer.context
19144
+ @param {string} context
19145
+ The context object.
19146
+
19147
+ If no context has been set an empty object is returned.
19148
+ @experimental
19149
+ */
18656
19150
  u.delegate(api, ['accept', 'dismiss', 'isRoot', 'isOverlay', 'isFront', 'on', 'off', 'emit', 'parent', 'historyVisible', 'location', 'mode', 'context', 'element', 'contains', 'size', 'affix'], function() {
18657
19151
  return stack.current;
18658
19152
  });
18659
19153
  return api;
18660
19154
  })();
18661
19155
 
18662
-
18663
- /***
18664
- TODO: Docs
18665
- @property up.context
18666
- @pram {Object} context
18667
- */
18668
-
18669
- u.getter(up, 'context', function() {
18670
- return up.layer.context;
18671
- });
18672
-
18673
19156
  }).call(this);
18674
19157
 
18675
19158
  /***
@@ -18742,6 +19225,11 @@ With these [`up-target`](/a-up-follow#up-target) annotations Unpoly only updates
18742
19225
  The JavaScript environment will persist and the user will not see a white flash while the
18743
19226
  new page is loading.
18744
19227
 
19228
+ @see a[up-follow]
19229
+ @see a[up-instant]
19230
+ @see a[up-preload]
19231
+ @see up.follow
19232
+
18745
19233
  @module up.link
18746
19234
  */
18747
19235
 
@@ -18749,7 +19237,7 @@ new page is loading.
18749
19237
  var slice = [].slice;
18750
19238
 
18751
19239
  up.link = (function() {
18752
- var ATTRIBUTES_SUGGESTING_FOLLOW, LINKS_WITH_LOCAL_HTML, LINKS_WITH_REMOTE_HTML, combineFollowableSelectors, config, convertClicks, didUserDragAway, e, follow, followMethod, followOptions, followURL, forkEventAsUpClick, fullClickableSelector, fullFollowSelector, fullInstantSelector, fullPreloadSelector, isFollowDisabled, isFollowable, isInstant, isInstantDisabled, isPreloadDisabled, isSafe, lastMousedownTarget, linkPreloader, makeClickable, makeFollowable, parseRequestOptions, preload, reset, shouldFollowEvent, shouldPreload, targetMacro, u, willCache;
19240
+ var ATTRIBUTES_SUGGESTING_FOLLOW, LINKS_WITH_LOCAL_HTML, LINKS_WITH_REMOTE_HTML, combineFollowableSelectors, config, convertClicks, didUserDragAway, e, follow, followMethod, followOptions, followURL, forkEventAsUpClick, fullClickableSelector, fullFollowSelector, fullInstantSelector, fullPreloadSelector, isFollowDisabled, isFollowable, isInstant, isInstantDisabled, isPreloadDisabled, isSafe, lastMousedownTarget, linkPreloader, makeClickable, makeFollowable, parseRequestOptions, preload, reset, shouldFollowEvent, shouldPreload, u, willCache;
18753
19241
  u = up.util;
18754
19242
  e = up.element;
18755
19243
  linkPreloader = new up.LinkPreloader();
@@ -18766,9 +19254,10 @@ new page is loading.
18766
19254
  };
18767
19255
 
18768
19256
  /***
18769
- TODO: Docs
18770
- TODO: Doucment that noInstantSelectors and noPreloadSelectors inherit from noFollowSelectors
18771
- TODO: Document that noFollowSelectors already excludes cross-origin, rel=download, [target], [href^=#], javascript: hrefs
19257
+ Configures defaults for link handling.
19258
+
19259
+ In particular you can configure Unpoly to handle [all links on the page](/handling-everything)
19260
+ without requiring developers to set `[up-...]` attributes.
18772
19261
 
18773
19262
  @property up.link.config
18774
19263
 
@@ -18841,7 +19330,7 @@ new page is loading.
18841
19330
 
18842
19331
  If set to `false`, Unpoly will never preload links.
18843
19332
 
18844
- @param {Array<string>} [config.cickableSelectors]
19333
+ @param {Array<string>} [config.clickableSelectors]
18845
19334
  A list of CSS selectors matching elements that should behave like links or buttons.
18846
19335
 
18847
19336
  @see [up-clickable]
@@ -18913,10 +19402,9 @@ new page is loading.
18913
19402
  };
18914
19403
 
18915
19404
  /***
18916
- Fetches the given link's `[href]` with JavaScript and [replaces](/up.replace) the
18917
- [current layer](/up.layer.current) with HTML from the response.
19405
+ Follows the given link with JavaScript and updates a fragment with the server response.
18918
19406
 
18919
- By default the layer's [main element](/main)
19407
+ By default the layer's [main element](/up-main)
18920
19408
  will be replaced. Attributes like `a[up-target]`
18921
19409
  or `a[up-layer]` will be honored.
18922
19410
 
@@ -18978,8 +19466,24 @@ new page is loading.
18978
19466
  };
18979
19467
 
18980
19468
  /***
18981
- Parses the `render()` options that would be used to
18982
- [`follow`](/up.follow) the given link, but does not [render](/up.render).
19469
+ Parses the [render](/up.render) options that would be used to
19470
+ [`follow`](/up.follow) the given link, but does not render.
19471
+
19472
+ \#\#\# Example
19473
+
19474
+ Given a link with some `[up-...]` attributes:
19475
+
19476
+ ```html
19477
+ <a href="/foo" up-target=".content" up-layer="new">...</a>
19478
+ ```
19479
+
19480
+ We can parse the link's render options like this:
19481
+
19482
+ ```js
19483
+ let link = document.querySelector('a[href="/foo"]')
19484
+ let options = up.link.followOptions(link)
19485
+ // => { url: '/foo', method: 'GET', target: '.content', layer: 'new', ... }
19486
+ ```
18983
19487
 
18984
19488
  @function up.link.followOptions
18985
19489
  @param {Element|jQuery|string} link
@@ -19058,7 +19562,20 @@ new page is loading.
19058
19562
 
19059
19563
  The event is emitted on the `<a>` element that is being followed.
19060
19564
 
19061
- TODO: Document that listeners may manipulate options
19565
+ \#\#\# Changing render options
19566
+
19567
+ Listeners may inspect and manipulate [render options](/up.render) for the coming fragment update.
19568
+
19569
+ The code below will open all form-contained links in an overlay, as to not
19570
+ lose the user's form data:
19571
+
19572
+ ```js
19573
+ up.on('up:link:follow', function(event, link) {
19574
+ if (link.closest('form')) {
19575
+ event.renderOptions.layer = 'new'
19576
+ }
19577
+ })
19578
+ ```
19062
19579
 
19063
19580
  @event up:link:follow
19064
19581
  @param {Element} event.target
@@ -19084,7 +19601,10 @@ new page is loading.
19084
19601
  @param {Object} options
19085
19602
  See options for `up.follow()`.
19086
19603
  @return {Promise}
19087
- A promise that will be fulfilled when the request was loaded and cached
19604
+ A promise that will be fulfilled when the request was loaded and cached.
19605
+
19606
+ When preloading is [disabled](/up.link.config#config.preloadEnabled) the promise
19607
+ rejects with an `AbortError`.
19088
19608
  @stable
19089
19609
  */
19090
19610
  preload = function(link, options) {
@@ -19188,7 +19708,7 @@ new page is loading.
19188
19708
  @function up.link.makeFollowable
19189
19709
  @param {Element|jQuery|string} link
19190
19710
  The element or selector for the link to make followable.
19191
- @stable
19711
+ @experimental
19192
19712
  */
19193
19713
  makeFollowable = function(link) {
19194
19714
  if (!isFollowable(link)) {
@@ -19324,6 +19844,13 @@ new page is loading.
19324
19844
  If the user activates an element using their keyboard, the `up:click` event will be emitted
19325
19845
  when the key is pressed even if the element has an `[up-instant]` attribute.
19326
19846
 
19847
+ \#\#\# Only unmodified clicks are considered
19848
+
19849
+ To prevent overriding native browser behavior, the `up:click` is only emitted for unmodified clicks.
19850
+
19851
+ In particular, it is not emitted when the user holds `Shift`, `CTRL` or `Meta` while clicking.
19852
+ Neither it is emitted when the user clicks with a secondary mouse button.
19853
+
19327
19854
  @event up:click
19328
19855
  @param {Element} event.target
19329
19856
  The clicked element.
@@ -19346,24 +19873,9 @@ new page is loading.
19346
19873
  method = followMethod(link);
19347
19874
  return up.network.isSafeMethod(method);
19348
19875
  };
19349
- targetMacro = function(queryAttr, fixedResultAttrs, callback) {
19350
- return up.macro("[" + queryAttr + "]", function(link) {
19351
- var optionalTarget, resultAttrs;
19352
- resultAttrs = u.copy(fixedResultAttrs);
19353
- if (optionalTarget = link.getAttribute(queryAttr)) {
19354
- resultAttrs['up-target'] = optionalTarget;
19355
- } else {
19356
- resultAttrs['up-follow'] = '';
19357
- }
19358
- e.setMissingAttrs(link, resultAttrs);
19359
- link.removeAttribute(queryAttr);
19360
- return typeof callback === "function" ? callback() : void 0;
19361
- });
19362
- };
19363
19876
 
19364
19877
  /***
19365
- [Follows](/up.follow) this link with JavaScript and replaces a CSS selector
19366
- on the current page with a corresponding element from the response.
19878
+ [Follows](/up.follow) this link with JavaScript and updates a fragment with the server response.
19367
19879
 
19368
19880
  Following a link is considered [navigation](/navigation) by default.
19369
19881
 
@@ -19376,7 +19888,7 @@ new page is loading.
19376
19888
  <a href="/posts/5" up-follow up-target=".content">Read post</a>
19377
19889
  ```
19378
19890
 
19379
- If no `[up-target]` attribute is set, the [main target](/main) is updated.
19891
+ If no `[up-target]` attribute is set, the [main target](/up-main) is updated.
19380
19892
 
19381
19893
  \#\#\# Advanced fragment changes
19382
19894
 
@@ -19413,14 +19925,14 @@ new page is loading.
19413
19925
  @param [up-target]
19414
19926
  The CSS selector to update.
19415
19927
 
19416
- If omitted a [main target](/main) will be rendered.
19928
+ If omitted a [main target](/up-main) will be rendered.
19417
19929
 
19418
19930
  @param [up-fallback]
19419
19931
  Specifies behavior if the [target selector](/up.render#options.target) is missing from the current page or the server response.
19420
19932
 
19421
19933
  If set to a CSS selector, Unpoly will attempt to replace that selector instead.
19422
19934
 
19423
- If set to `true` Unpoly will attempt to replace a [main target](/main) instead.
19935
+ If set to `true` Unpoly will attempt to replace a [main target](/up-main) instead.
19424
19936
 
19425
19937
  If set to `false` Unpoly will immediately reject the render promise.
19426
19938
 
@@ -19494,12 +20006,12 @@ new page is loading.
19494
20006
 
19495
20007
  If set to `auto` history will be updated if the `[up-target]` matches
19496
20008
  a selector in `up.fragment.config.autoHistoryTargets`. By default this contains all
19497
- [main targets](/main).
20009
+ [main targets](/up-main).
19498
20010
 
19499
20011
  If set to `false`, the history will remain unchanged.
19500
20012
 
19501
20013
  [Overlays](/up.layer) will only change the browser URL and window title if the overlay
19502
- has [visible history](/up.layer.historyVisible), even with `{ history: true }`.
20014
+ has [visible history](/up.layer.historyVisible), even when `[up-history=true]` is set.
19503
20015
 
19504
20016
  @param [up-title]
19505
20017
  An explicit document title to use after rendering.
@@ -19574,7 +20086,7 @@ new page is loading.
19574
20086
  This is only relevant when updating a layer that is not the [frontmost layer](/up.layer.front).
19575
20087
 
19576
20088
  @param [up-context]
19577
- A JSON object that will be merged into the [context](/up.context)
20089
+ A JSON object that will be merged into the [context](/context)
19578
20090
  of the current layer once the fragment is rendered.
19579
20091
 
19580
20092
  @param [up-keep='true']
@@ -19629,12 +20141,7 @@ new page is loading.
19629
20141
  });
19630
20142
 
19631
20143
  /***
19632
- TODO: Explain that this generates an up:click event, works on any elements, can can be used to accelerate links
19633
-
19634
- By adding an `up-instant` attribute to a link, the destination will be
19635
- fetched on `mousedown` instead of `click` (`mouseup`).
19636
-
19637
- <a href="/users" up-follow up-instant>User list</a>
20144
+ Follows this link on `mousedown` instead of `click`.
19638
20145
 
19639
20146
  This will save precious milliseconds that otherwise spent
19640
20147
  on waiting for the user to release the mouse button. Since an
@@ -19646,6 +20153,10 @@ new page is loading.
19646
20153
  navigation actions this isn't needed. E.g. popular operation
19647
20154
  systems switch tabs on `mousedown` instead of `click`.
19648
20155
 
20156
+ \#\#\# Example
20157
+
20158
+ <a href="/users" up-follow up-instant>User list</a>
20159
+
19649
20160
  \#\#\# Accessibility
19650
20161
 
19651
20162
  If the user activates an element using their keyboard, the `up:click` event will be emitted
@@ -19655,37 +20166,6 @@ new page is loading.
19655
20166
  @stable
19656
20167
  */
19657
20168
 
19658
- /***
19659
- [Follows](/up.follow) this link as fast as possible.
19660
-
19661
- This is done by:
19662
-
19663
- - [Following the link through AJAX](/a-up-follow) instead of a full page load
19664
- - [Preloading the link's destination URL](/a-up-preload)
19665
- - [Triggering the link on `mousedown`](/a-up-instant) instead of on `click`
19666
-
19667
- \#\#\# Example
19668
-
19669
- Use `[up-dash]` like this:
19670
-
19671
- <a href="/users" up-dash=".main">User list</a>
19672
-
19673
- This is shorthand for:
19674
-
19675
- <a href="/users" up-target=".main" up-instant up-preload>User list</a>
19676
-
19677
- @selector a[up-dash]
19678
- @param [up-dash='body']
19679
- The CSS selector to replace
19680
-
19681
- Inside the CSS selector you may refer to this link as `&` ([like in Sass](https://sass-lang.com/documentation/file.SASS_REFERENCE.html#parent-selector)).
19682
- @stable
19683
- */
19684
- targetMacro('up-dash', {
19685
- 'up-preload': '',
19686
- 'up-instant': ''
19687
- });
19688
-
19689
20169
  /***
19690
20170
  Add an `[up-expand]` attribute to any element to enlarge the click area of a
19691
20171
  descendant link.
@@ -19744,11 +20224,9 @@ new page is loading.
19744
20224
  });
19745
20225
 
19746
20226
  /***
19747
- Links with an `up-preload` attribute will silently fetch their target
19748
- when the user hovers over the click area, or when the user puts her
19749
- mouse/finger down (before releasing).
20227
+ Preloads this link when the user hovers over it.
19750
20228
 
19751
- When the link is clicked later, the response will already be cached,
20229
+ When the link is clicked later the response will already be cached,
19752
20230
  making the interaction feel instant.
19753
20231
 
19754
20232
  @selector a[up-preload]
@@ -19776,7 +20254,6 @@ new page is loading.
19776
20254
  isFollowable: isFollowable,
19777
20255
  shouldFollowEvent: shouldFollowEvent,
19778
20256
  followMethod: followMethod,
19779
- targetMacro: targetMacro,
19780
20257
  convertClicks: convertClicks,
19781
20258
  config: config,
19782
20259
  combineFollowableSelectors: combineFollowableSelectors
@@ -19791,9 +20268,12 @@ new page is loading.
19791
20268
  Forms
19792
20269
  =====
19793
20270
 
19794
- Unpoly comes with functionality to [submit](/form-up-submit) and [validate](/input-up-validate)
19795
- forms without leaving the current page. This means you can replace page fragments,
19796
- open dialogs with sub-forms, etc. all without losing form state.
20271
+ The `up.form` module helps you work with non-trivial forms.
20272
+
20273
+ @see form[up-submit]
20274
+ @see form[up-validate]
20275
+ @see input[up-switch]
20276
+ @see form[up-autosubmit]
19797
20277
 
19798
20278
  @module up.form
19799
20279
  */
@@ -19802,7 +20282,7 @@ open dialogs with sub-forms, etc. all without losing form state.
19802
20282
  var slice = [].slice;
19803
20283
 
19804
20284
  up.form = (function() {
19805
- var ATTRIBUTES_SUGGESTING_SUBMIT, abortScheduledValidate, autosubmit, config, e, fieldSelector, findFields, findSwitcherForTarget, findValidateTarget, findValidateTargetFromConfig, focusedField, fullSubmitSelector, getContainer, isSubmitDisabled, observe, observeCallbackFromElement, reset, submit, submitButtonSelector, submitOptions, submittingButton, switchTarget, switchTargets, switcherValues, u, validate;
20285
+ var ATTRIBUTES_SUGGESTING_SUBMIT, abortScheduledValidate, autosubmit, config, e, fieldSelector, findFields, findSwitcherForTarget, findValidateTarget, findValidateTargetFromConfig, focusedField, fullSubmitSelector, getContainer, isSubmitDisabled, isSubmittable, observe, observeCallbackFromElement, reset, submit, submitButtonSelector, submitOptions, submittingButton, switchTarget, switchTargets, switcherValues, u, validate;
19806
20286
  u = up.util;
19807
20287
  e = up.element;
19808
20288
  ATTRIBUTES_SUGGESTING_SUBMIT = ['[up-submit]', '[up-target]', '[up-layer]', '[up-transition]'];
@@ -19979,8 +20459,26 @@ open dialogs with sub-forms, etc. all without losing form state.
19979
20459
  });
19980
20460
 
19981
20461
  /***
19982
- Parses the `render()` options that would be used to
19983
- [`submit`](/up.submit) the given form, but does not [render](/up.render).
20462
+ Parses the [render](/up.render) options that would be used to
20463
+ [`submit`](/up.submit) the given form, but does not render.
20464
+
20465
+ \#\#\# Example
20466
+
20467
+ Given a form element:
20468
+
20469
+ ```html
20470
+ <form action="/foo" method="post" up-target=".content">
20471
+ ...
20472
+ </form>
20473
+ ```
20474
+
20475
+ We can parse the link's render options like this:
20476
+
20477
+ ```js
20478
+ let form = document.querySelector('form')
20479
+ let options = up.form.submitOptions(form)
20480
+ // => { url: '/foo', method: 'POST', target: '.content', ... }
20481
+ ```
19984
20482
 
19985
20483
  @param {Element|jQuery|string} form
19986
20484
  The form to submit.
@@ -20033,14 +20531,29 @@ open dialogs with sub-forms, etc. all without losing form state.
20033
20531
  /***
20034
20532
  This event is [emitted](/up.emit) when a form is [submitted](/up.submit) through Unpoly.
20035
20533
 
20036
- The event is emitted on the`<form>` element.
20534
+ The event is emitted on the `<form>` element.
20535
+
20536
+ When the form is being [validated](/input-up-validate), this event is not emitted.
20537
+ Instead an `up:form:validate` event is emitted.
20538
+
20539
+ \#\#\# Changing render options
20540
+
20541
+ Listeners may inspect and manipulate [render options](/up.render) for the coming fragment update.
20542
+
20543
+ The code below will use a custom [transition](/up-transition)
20544
+ when a form submission [fails](/server-errors):
20545
+
20546
+ ```js
20547
+ up.on('up:form:submit', function(event, form) {
20548
+ event.renderOptions.failTransition = 'shake'
20549
+ })
20550
+ ```
20037
20551
 
20038
20552
  @event up:form:submit
20039
20553
  @param {Element} event.target
20040
20554
  The `<form>` element that will be submitted.
20041
20555
  @param {Object} event.renderOptions
20042
20556
  An object with [render options](/up.render) for the fragment update
20043
- that will show the validation results.
20044
20557
 
20045
20558
  Listeners may inspect and modify these options.
20046
20559
  @param event.preventDefault()
@@ -20048,7 +20561,11 @@ open dialogs with sub-forms, etc. all without losing form state.
20048
20561
  @stable
20049
20562
  */
20050
20563
  up.on('up:click', submitButtonSelector, function(event, button) {
20051
- return button.focus();
20564
+ var form;
20565
+ form = e.closest(button, 'form');
20566
+ if (form && isSubmittable(form)) {
20567
+ return button.focus();
20568
+ }
20052
20569
  });
20053
20570
 
20054
20571
  /***
@@ -20133,10 +20650,10 @@ open dialogs with sub-forms, etc. all without losing form state.
20133
20650
  /***
20134
20651
  [Observes](/up.observe) a field or form and submits the form when a value changes.
20135
20652
 
20136
- Both the form and the changed field will be assigned a CSS class [`form-up-active`](/form-up-active)
20653
+ Both the form and the changed field will be assigned a CSS class [`.up-active`](/form-up-active)
20137
20654
  while the autosubmitted form is processing.
20138
20655
 
20139
- The unobtrusive variant of this is the [`up-autosubmit`](/form-up-autosubmit) attribute.
20656
+ The unobtrusive variant of this is the [`[up-autosubmit]`](/form-up-autosubmit) attribute.
20140
20657
 
20141
20658
  @function up.autosubmit
20142
20659
  @param {string|Element|jQuery} target
@@ -20190,7 +20707,9 @@ open dialogs with sub-forms, etc. all without losing form state.
20190
20707
 
20191
20708
  \#\#\# Example
20192
20709
 
20193
- up.validate('input[name=email]', { target: '.email-errors' })
20710
+ ```js
20711
+ up.validate('input[name=email]', { target: '.email-errors' })
20712
+ ```
20194
20713
 
20195
20714
  @function up.validate
20196
20715
  @param {string|Element|jQuery} field
@@ -20234,6 +20753,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20234
20753
  @param event.preventDefault()
20235
20754
  Event listeners may call this method to prevent the validation request
20236
20755
  being sent to the server.
20756
+ @stable
20237
20757
  */
20238
20758
  switcherValues = function(field) {
20239
20759
  var checkedButton, form, groupName, meta, value, values;
@@ -20346,24 +20866,51 @@ open dialogs with sub-forms, etc. all without losing form state.
20346
20866
  return element;
20347
20867
  }
20348
20868
  };
20869
+
20870
+ /***
20871
+ Returns whether the given form will be [submitted](/up.follow) through Unpoly
20872
+ instead of making a full page load.
20873
+
20874
+ By default Unpoly will follow forms if the element has
20875
+ one of the following attributes:
20876
+
20877
+ - `[up-submit]`
20878
+ - `[up-target]`
20879
+ - `[up-layer]`
20880
+ - `[up-transition]`
20881
+
20882
+ To consider other selectors to be submittable, see `up.form.config.submitSelectors`.
20883
+
20884
+ @function up.form.isSubmittable
20885
+ @param {Element|jQuery|string} form
20886
+ The form to check.
20887
+ @stable
20888
+ */
20889
+ isSubmittable = function(form) {
20890
+ form = up.fragment.get(form);
20891
+ return e.matches(form, fullSubmitSelector()) && !isSubmitDisabled(form);
20892
+ };
20349
20893
  isSubmitDisabled = function(form) {
20350
20894
  return e.matches(form, config.noSubmitSelectors.join(','));
20351
20895
  };
20352
20896
 
20353
20897
  /***
20354
- Forms with an `up-target` attribute are [submitted via AJAX](/up.submit)
20355
- instead of triggering a full page reload.
20356
-
20357
- <form method="post" action="/users" up-target=".main">
20358
- ...
20359
- </form>
20898
+ Submits this form via JavaScript and updates a fragment with the server response.
20360
20899
 
20361
20900
  The server response is searched for the selector given in `up-target`.
20362
20901
  The selector content is then [replaced](/up.replace) in the current page.
20363
20902
 
20364
20903
  The programmatic variant of this is the [`up.submit()`](/up.submit) function.
20365
20904
 
20366
- \#\#\# Failed submission
20905
+ \#\#\# Example
20906
+
20907
+ ```html
20908
+ <form method="post" action="/users" up-submit>
20909
+ ...
20910
+ </form>
20911
+ ```
20912
+
20913
+ \#\#\# Handling validation errors
20367
20914
 
20368
20915
  When the server was unable to save the form due to invalid params,
20369
20916
  it will usually re-render an updated copy of the form with
@@ -20378,19 +20925,35 @@ open dialogs with sub-forms, etc. all without losing form state.
20378
20925
  [`:status` option to `render`](http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option)
20379
20926
  for this:
20380
20927
 
20381
- class UsersController < ApplicationController
20382
-
20383
- def create
20384
- user_params = params[:user].permit(:email, :password)
20385
- @user = User.new(user_params)
20386
- if @user.save?
20387
- sign_in @user
20388
- else
20389
- render 'form', status: :bad_request
20390
- end
20391
- end
20928
+ ```ruby
20929
+ class UsersController < ApplicationController
20392
20930
 
20931
+ def create
20932
+ user_params = params[:user].permit(:email, :password)
20933
+ @user = User.new(user_params)
20934
+ if @user.save?
20935
+ sign_in @user
20936
+ else
20937
+ render 'form', status: :bad_request
20393
20938
  end
20939
+ end
20940
+
20941
+ end
20942
+ ```
20943
+
20944
+ You may define different option for the failure case by infixing an attribute with `fail`:
20945
+
20946
+ ```html
20947
+ <form method="post" action="/action"
20948
+ up-target=".content"
20949
+ up-fail-target="form"
20950
+ up-scroll="auto"
20951
+ up-fail-scroll=".errors">
20952
+ ...
20953
+ </form>
20954
+ ```
20955
+
20956
+ See [handling server errors](/server-errors) for details.
20394
20957
 
20395
20958
  Note that you can also use
20396
20959
  [`input[up-validate]`](/input-up-validate) to perform server-side
@@ -20398,7 +20961,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20398
20961
 
20399
20962
  \#\#\# Giving feedback while the form is processing
20400
20963
 
20401
- The `<form>` element will be assigned a CSS class [`up-active`](/form.up-active) while
20964
+ The `<form>` element will be assigned a CSS class [`.up-active`](/form.up-active) while
20402
20965
  the submission is loading.
20403
20966
 
20404
20967
  \#\#\# Short notation
@@ -20582,11 +21145,13 @@ open dialogs with sub-forms, etc. all without losing form state.
20582
21145
  */
20583
21146
 
20584
21147
  /***
20585
- Performs [server-side validation](/input-up-validate) when any fieldset within this form changes.
21148
+ Validates this form on the server when any field changes and shows validation errors.
20586
21149
 
20587
21150
  You can configure what Unpoly considers a fieldset by adding CSS selectors to the
20588
21151
  `up.form.config.validateTargets` array.
20589
21152
 
21153
+ See `input[up-validate]` for detailed documentation.
21154
+
20590
21155
  @selector form[up-validate]
20591
21156
  @param up-validate
20592
21157
  The CSS selector to update with the server response.
@@ -20603,7 +21168,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20603
21168
  });
20604
21169
 
20605
21170
  /***
20606
- Show or hide elements when a `<select>` or `<input>` has a given value.
21171
+ Show or hide elements when a form field is set to a given value.
20607
21172
 
20608
21173
  \#\#\# Example: Select options
20609
21174
 
@@ -20806,7 +21371,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20806
21371
  /***
20807
21372
  Submits this field's form when this field changes its values.
20808
21373
 
20809
- Both the form and the changed field will be assigned a CSS class [`up-active`](/form-up-active)
21374
+ Both the form and the changed field will be assigned a CSS class [`.up-active`](/form-up-active)
20810
21375
  while the autosubmitted form is loading.
20811
21376
 
20812
21377
  The programmatic variant of this is the [`up.autosubmit()`](/up.autosubmit) function.
@@ -20835,15 +21400,15 @@ open dialogs with sub-forms, etc. all without losing form state.
20835
21400
  </div>
20836
21401
 
20837
21402
  @selector input[up-autosubmit]
20838
- @param up-delay
21403
+ @param [up-delay]
20839
21404
  The number of miliseconds to wait after a change before the form is submitted.
20840
21405
  @stable
20841
21406
  */
20842
21407
 
20843
21408
  /***
20844
- Submits the form when *any* field changes.
21409
+ Submits the form when any field changes.
20845
21410
 
20846
- Both the form and the field will be assigned a CSS class [`up-active`](/form-up-active)
21411
+ Both the form and the field will be assigned a CSS class [`.up-active`](/form-up-active)
20847
21412
  while the autosubmitted form is loading.
20848
21413
 
20849
21414
  The programmatic variant of this is the [`up.autosubmit()`](/up.autosubmit) function.
@@ -20858,7 +21423,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20858
21423
  </form>
20859
21424
 
20860
21425
  @selector form[up-autosubmit]
20861
- @param up-delay
21426
+ @param [up-delay]
20862
21427
  The number of miliseconds to wait after a change before the form is submitted.
20863
21428
  @stable
20864
21429
  */
@@ -20870,6 +21435,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20870
21435
  config: config,
20871
21436
  submit: submit,
20872
21437
  submitOptions: submitOptions,
21438
+ isSubmittable: isSubmittable,
20873
21439
  observe: observe,
20874
21440
  validate: validate,
20875
21441
  autosubmit: autosubmit,
@@ -20895,44 +21461,57 @@ Navigation feedback
20895
21461
  ===================
20896
21462
 
20897
21463
  The `up.feedback` module adds useful CSS classes to links while they are loading,
20898
- or when they point to the current URL. By styling these classes you may
20899
- provide instant feedback to user interactions. This improves the perceived speed of your interface.
21464
+ or when they point to the current URL.
21465
+
21466
+ By styling these classes you may provide instant feedback to user interactions,
21467
+ improving the perceived speed of your interface.
20900
21468
 
20901
21469
 
20902
21470
  \#\#\# Example
20903
21471
 
20904
21472
  Let's say we have an `<nav>` element with two links, pointing to `/foo` and `/bar` respectively:
20905
21473
 
20906
- <nav>
20907
- <a href="/foo" up-follow>Foo</a>
20908
- <a href="/bar" up-follow>Bar</a>
20909
- </nav>
21474
+ ```html
21475
+ <nav>
21476
+ <a href="/foo" up-follow>Foo</a>
21477
+ <a href="/bar" up-follow>Bar</a>
21478
+ </nav>
21479
+ ```
20910
21480
 
20911
21481
  By giving the navigation bar the `[up-nav]` attribute, links pointing to the current browser address are highlighted
20912
21482
  as we navigate through the site.
20913
21483
 
20914
21484
  If the current URL is `/foo`, the first link is automatically marked with an [`.up-current`](/a.up-current) class:
20915
21485
 
20916
- <nav up-nav>
20917
- <a href="/foo" up-follow class="up-current">Foo</a>
20918
- <a href="/bar" up-follow>Bar</a>
20919
- </nav>
21486
+ ```html
21487
+ <nav up-nav>
21488
+ <a href="/foo" up-follow class="up-current">Foo</a>
21489
+ <a href="/bar" up-follow>Bar</a>
21490
+ </nav>
21491
+ ```
20920
21492
 
20921
21493
  When the user clicks on the `/bar` link, the link will receive the [`up-active`](/a.up-active) class while it is waiting
20922
21494
  for the server to respond:
20923
21495
 
20924
- <nav up-nav>
20925
- <a href="/foo" up-follow class="up-current">Foo</a>
20926
- <a href="/bar" up-follow class="up-active">Bar</a>
20927
- </div>
21496
+ ```
21497
+ <nav up-nav>
21498
+ <a href="/foo" up-follow class="up-current">Foo</a>
21499
+ <a href="/bar" up-follow class="up-active">Bar</a>
21500
+ </div>
21501
+ ```
20928
21502
 
20929
21503
  Once the response is received the URL will change to `/bar` and the `up-active` class is removed:
20930
21504
 
20931
- <nav up-nav>
20932
- <a href="/foo" up-follow>Foo</a>
20933
- <a href="/bar" up-follow class="up-current">Bar</a>
20934
- </nav>
21505
+ ```html
21506
+ <nav up-nav>
21507
+ <a href="/foo" up-follow>Foo</a>
21508
+ <a href="/bar" up-follow class="up-current">Bar</a>
21509
+ </nav>
21510
+ ```
20935
21511
 
21512
+ @see [up-nav]
21513
+ @see a.up-current
21514
+ @see a.up-active
20936
21515
 
20937
21516
  @module up.feedback
20938
21517
  */
@@ -21234,7 +21813,7 @@ Once the response is received the URL will change to `/bar` and the `up-active`
21234
21813
  */
21235
21814
 
21236
21815
  /***
21237
- Links within `[up-nav]` may use the `[up-alias]` attribute to pass an [URL pattern](/url-patterns) for which they
21816
+ Links within `[up-nav]` may use the `[up-alias]` attribute to pass a [URL pattern](/url-patterns) for which they
21238
21817
  should also be highlighted as [`.up-current`](a.up-current).
21239
21818
 
21240
21819
  \#\#\# Example
@@ -21247,7 +21826,7 @@ Once the response is received the URL will change to `/bar` and the `up-active`
21247
21826
  </div>
21248
21827
  ```
21249
21828
 
21250
- To pass more than one alternative URLs, use an [URL pattern](/url-patterns).
21829
+ To pass more than one alternative URLs, use a [URL pattern](/url-patterns).
21251
21830
 
21252
21831
  @selector a[up-alias]
21253
21832
  @param up-alias
@@ -21307,8 +21886,10 @@ Once the response is received the URL will change to `/bar` and the `up-active`
21307
21886
  Passive updates
21308
21887
  ===============
21309
21888
 
21310
- This work-in-progress package will contain functionality to
21311
- passively receive updates from the server.
21889
+ This package contains functionality to passively receive updates from the server.
21890
+
21891
+ @see [up-hungry]
21892
+ @see [up-poll]
21312
21893
 
21313
21894
  @module up.radio
21314
21895
  */
@@ -21323,13 +21904,16 @@ passively receive updates from the server.
21323
21904
  Configures defaults for passive updates.
21324
21905
 
21325
21906
  @property up.radio.config
21907
+
21326
21908
  @param {Array<string>} [config.hungrySelectors]
21327
21909
  An array of CSS selectors that is replaced whenever a matching element is found in a response.
21328
21910
  These elements are replaced even when they were not targeted directly.
21329
21911
 
21330
21912
  By default this contains the [`[up-hungry]`](/up-hungry) attribute.
21913
+
21331
21914
  @param {number} [config.pollInterval=30000]
21332
21915
  The default [polling](/up-poll] interval in milliseconds.
21916
+
21333
21917
  @param {boolean|string|Function(Element)} [config.pollEnabled=true]
21334
21918
  Whether Unpoly will follow instructions to poll fragments, like the `[up-poll]` attribute.
21335
21919
 
@@ -21344,6 +21928,7 @@ passively receive updates from the server.
21344
21928
  When set to `false`, Unpoly will never allow polling.
21345
21929
 
21346
21930
  You may also pass a function that accepts the polling fragment and returns `true`, `false` or `'auto'`.
21931
+
21347
21932
  @stable
21348
21933
  */
21349
21934
  config = new up.Config(function() {
@@ -21366,9 +21951,8 @@ passively receive updates from the server.
21366
21951
  };
21367
21952
 
21368
21953
  /***
21369
- Elements with an `[up-hungry]` attribute are [updated](/up.replace) whenever there is a
21370
- matching element found in a successful response. The element is replaced even
21371
- when it isn't targeted directly.
21954
+ Elements with an `[up-hungry]` attribute are updated whenever the server
21955
+ sends a matching element, even if the element isn't targeted.
21372
21956
 
21373
21957
  Use cases for this are unread message counters or notification flashes.
21374
21958
  Such elements often live in the layout, outside of the content area that is
@@ -21460,21 +22044,27 @@ passively receive updates from the server.
21460
22044
  Assume an application layout with an unread message counter.
21461
22045
  You can use `[up-poll]` to refresh the counter every 30 seconds:
21462
22046
 
21463
- <div class="unread-count" up-poll>
21464
- 2 new messages
21465
- </div>
22047
+ ```html
22048
+ <div class="unread-count" up-poll>
22049
+ 2 new messages
22050
+ </div>
22051
+ ```
21466
22052
 
21467
22053
  \#\#\# Controlling the reload interval
21468
22054
 
21469
22055
  You may set an optional `[up-interval]` attribute to set the reload interval in milliseconds:
21470
22056
 
21471
- <div class="unread-count" up-poll up-interval="10000">
21472
- 2 new messages
21473
- </div>
22057
+ ```html
22058
+ <div class="unread-count" up-poll up-interval="10000">
22059
+ 2 new messages
22060
+ </div>
22061
+ ```
21474
22062
 
21475
22063
  If the value is omitted, a global default is used. You may configure the default like this:
21476
22064
 
21477
- up.radio.config.pollInterval = 10000
22065
+ ```js
22066
+ up.radio.config.pollInterval = 10000
22067
+ ```
21478
22068
 
21479
22069
  \#\#\# Controlling the source URL
21480
22070
 
@@ -21482,13 +22072,20 @@ passively receive updates from the server.
21482
22072
 
21483
22073
  To reload from another URL, set an `[up-source]` attribute on the polling element:
21484
22074
 
21485
- <div class="unread-count" up-poll up-source="/unread-count">
21486
- 2 new messages
21487
- </div>
22075
+ ```html
22076
+ <div class="unread-count" up-poll up-source="/unread-count">
22077
+ 2 new messages
22078
+ </div>
22079
+ ```
21488
22080
 
21489
22081
  \#\#\# Skipping updates when nothing changed
21490
22082
 
21491
- TODO: Document [up-time] and X-Up-Reload-From-Time (currently both documented in `X-Up-Reload-From-Time`).
22083
+ When polling a fragment periodically we want to avoid rendering unchanged content.
22084
+ This saves <b>CPU time</b> and reduces the <b>bandwidth cost</b> for a
22085
+ request/response exchange to **~1 KB**.
22086
+
22087
+ To achieve this we timestamp your fragments with an `[up-time]` attribute to indicate
22088
+ when the underlying data was last changed. See `[up-time]` for a detailed example.
21492
22089
 
21493
22090
  @selector [up-poll]
21494
22091
  @param [up-interval]