unpoly-rails 2.0.0.pre.rc7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee83873d9c7f873fadc60c7492768b88d15a74a6a835283b1c7ab80c2de08ab0
4
- data.tar.gz: b1fdcc27628534630d100b5f5b728147b9155865b141a02dd3944c6857e9e1dc
3
+ metadata.gz: 60a37ba382e3664b7224d805da146e4a7364e7880dbcdb80580a0e9ef4406672
4
+ data.tar.gz: 8d899df9850761c7b07849b2ded8a241e334c9e4cbc3ac8dc5003af0629206ad
5
5
  SHA512:
6
- metadata.gz: e930f20386dbb9ac7cf8eb0171850f9a2a27bc46274b2b351d558f0cb8f054ba05beb3ca325b3d09de6c441d828f862c4fb84ec8bc17196607cf5ab453b78a74
7
- data.tar.gz: f736ba5790176658ae0eef6d6fdd3228c9808f9ae3368dd08ea81ddbe1bbee5fa84e8d2818fe78d209f12d315effe7f2612054c0872f810f9cf195b73ef1af0d
6
+ metadata.gz: 9caee93e9aa5f35eb7d7dcb276f1e48b1231b2f003e3bd56285105869f15759cbf7d2cfc57cf66dd2470b85df54775826352ea568e81f1151d1a981c04f0bc69
7
+ data.tar.gz: e53cee4842b88880f71769552dee074e4f865bfbae43033daf6c6a13950c73f0e5bf284ab7b9babfaff5677400ae0811111a8fac9dbafdd6a53e8a67b8c67796
data/CHANGELOG.md CHANGED
@@ -3,67 +3,135 @@ 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
 
9
11
  2.0.0
10
12
  -----
11
13
 
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.
14
+ Unpoly 2 ships with many new features and API improvements, unlocking many use cases that were not possible with Unpoly 1.
15
+
16
+ For an in-depth guide to all changes, see our [Unpoly 2 presentation](http://triskweline.de/unpoly2-slides/) (150 slides).
17
+
18
+ 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).
19
+
20
+ ### Change overview
21
+
22
+ #### Less need for boilerplate configuration
23
+
24
+ - 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.
25
+ - Unpoly can be configured to [handle all links and forms](/handling-everything), without any `[up-...]` attributes.
26
+ - We have examined many real-world Unpoly apps for repetitive configuration and made these options the new default.
27
+
28
+ #### New Layer API
29
+
30
+ - A new [layer API](/up.layer) replaces modals and popups.
31
+ - Layers can be stacked infinitely.
32
+ - 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).
33
+ - 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).
34
+
35
+ #### Subinteractions
36
+
37
+ - Overlays allow you to break up a complex screen into [subinteractions](/subinteractions).
38
+ - Subinteractions take place in overlays and may span one or many pages. The original screen remains open in the background.
39
+ - Once the subinteraction is *done*, the overlay is [closed](/closing-overlays) and a result value is communicated back to the parent layer.
40
+
41
+ #### Navigation intent
42
+
43
+ - You can now define whether a framgent update constitutes a user navigation. Switching screens needs other defaults than updating a tiny box.
44
+ - User navigation aborts earlier requests, fixing race conditions on slow connections.
45
+
46
+ #### Accessibility
47
+
48
+ - New overlays are focused automatically and trap focus in a cycle. Closing the overlay re-focuses the link that opened it.
49
+ - Focus is automatically managed when rendering major new content. A new [`[up-focus]` attribute](/focus-option) allows
50
+ you to explicitely move the user's focus as you update fragments.
51
+ - Keyboard navigation is supported everywhere.
52
+ - Focus, selection and scroll positions are preserved within an updated fragment.
53
+
54
+ #### Reworked Bootstrap integration
55
+
56
+ - The Bootstrap integration is now minimal and as unopinionated as possible. Little to no Bootstrap CSS is overridden.
57
+ - Bootstrap versions 3, 4 and 5 are now supported.
58
+
59
+ #### Quality of live improvements
60
+
61
+ - Unpoly now ships with a bandwidth-friendly [polling implementation](/up-poll) that handles many edge cases.
62
+ - 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.
63
+ - The [log](/up.log) output is more much more compact and has a calmer formatting.
64
+ - 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.
65
+ - History is no longer changed by default. Instead Unpoly updates history only when a [main target](/up-main) has changed.
66
+ - All scroll-related options have been unified in a single [`[up-scroll]` attribute](/scroll-option).
67
+ - 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.
68
+ - The client-side cache can be carefully managed by both the client and server.
69
+ - 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()`.
70
+ - Event handlers to `up:link:follow`, `up:form:submit` etc. may change the render options for the coming fragment update.
71
+ - Added more options to handle [unexpected server responses](/server-errors), including the new `up:fragment:loaded` event.
72
+
73
+ #### Extended server protocol
74
+
75
+ The optional server protocol has been extended with additional headers that the server may use to interact with the frontend. For example:
76
+
77
+ - The server may [emit events on the frontend](/X-Up-Events).
78
+ - The server may [close overlays](/X-Up-Accept).
79
+ - The server may [change the render target](/X-Up-Target) for a fragment update.
80
+
81
+ See `up.protocol` for a full list of features.
82
+
83
+ If you are using Ruby on Rails, the new protocol is already implemented by the [`unpoly-rails`](https://rubygems.org/gems/unpoly-rails) gem.
84
+
85
+ If you are using Elixir / Phoenix, the new protocol is already implemented by the [`ex_unpoly`](https://hex.pm/packages/ex_unpoly) package.
86
+
87
+
88
+ ### Overview of breaking changes
89
+
90
+ Please use [`unpoly-migrate.js`](/changes/upgrading) for a very smooth upgrade process from Unpoly 0.x or 1.x to Unpoly 2.0.
91
+
92
+ 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.
93
+
94
+ There's a short list of changes that we cannot fix with aliases.
95
+
96
+ #### Overlays (modals, popups) have different HTML
97
+
98
+ But it's similar. E.g. `<div class="modal">` becomes `<up-modal>`.
99
+
100
+ #### Unpoly only sees the current layer
101
+
102
+ You can target other layers with `{ layer: 'any' }`.
103
+
104
+ #### Async functions no longer wait for animations
105
+
106
+ You might or might not notice. In cases where you absolutely do need to wait, an `{ onFinished }` callback can be used.
107
+
108
+ #### Tooltips are no longer built-in
109
+
110
+ But there are a million better libraries.
111
+
112
+
113
+ ### Unpoly 1 maintenance
114
+
115
+ 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.
116
+
117
+ The legacy documentation for Unpoly 1.x has been archived to <https://v1.unpoly.com>.
118
+
60
119
 
61
120
 
62
121
  1.0.0
63
122
  -----
64
123
 
65
- - TODO
124
+ 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.
125
+
126
+ There are only three changes from 0.62.1:
127
+
128
+ - Fix a bug where `up.util.escapeHTML()`` would not escape single quotes.
129
+ - 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.
130
+ - You may now disable the Unpoly banner in the development console with `up.log.config.banner = false`. (change by @hfjallemark).
131
+
132
+ 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
133
 
134
+ 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
135
 
68
136
 
69
137
  0.62.1
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [Unpoly](https://unpoly.com)
1
+ [Unpoly 2](https://unpoly.com)
2
2
  ======
3
3
 
4
4
  Unobtrusive JavaScript framework for server-side applications
@@ -6,7 +6,9 @@ Unobtrusive JavaScript framework for server-side applications
6
6
 
7
7
  [Unpoly](https://unpoly.com) enables fast and flexible frontends with minimal changes to your server-side code.
8
8
 
9
- This repository is home to both the Unpoly JavaScript code and its (optional) bindings for Ruby on Rails (`unpoly-rails` gem).
9
+ This repository is home to both the Unpoly 2 JavaScript code and its (optional) bindings for Ruby on Rails (`unpoly-rails` gem).
10
+
11
+ If you're looking for the code of Unpoly 0.x or 1.0, use the [`1.x-stable`](https://github.com/unpoly/unpoly/tree/1.x-stable) branch.
10
12
 
11
13
 
12
14
  Getting started
@@ -33,6 +35,7 @@ Install dependencies for tests:
33
35
 
34
36
  - Install Ruby 2.3.8
35
37
  - Install Bundler by running `gem install bundler`
38
+ - Install Node.js (required for building the library)
36
39
  - `cd` into `spec_app`
37
40
  - Install dependencies by running `bundle install`
38
41
 
@@ -50,11 +53,9 @@ To run RSpec tests for the `unpoly-rails` gem:
50
53
 
51
54
  ### Making a new release
52
55
 
53
- We are currently feeding four release channels:
56
+ We are currently feeding two release channels:
54
57
 
55
- - Manual download from GitHub
56
58
  - npm
57
- - Bower (which is based on Git and version tags)
58
59
  - Rubygems (as the `unpoly-rails` gem)
59
60
 
60
61
  We always release to all channel simultaneously.
@@ -300,6 +300,41 @@ 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 u;
306
+
307
+ u = up.util;
308
+
309
+ up.migrate.postCompile = function(elements, compiler) {
310
+ var element, i, keepValue, len, results, value;
311
+ if (keepValue = compiler.keep) {
312
+ up.migrate.warn('The { keep: true } option for up.compiler() has been removed. Have the compiler set [up-keep] attribute instead.');
313
+ value = u.isString(keepValue) ? keepValue : '';
314
+ results = [];
315
+ for (i = 0, len = elements.length; i < len; i++) {
316
+ element = elements[i];
317
+ results.push(element.setAttribute('up-keep', value));
318
+ }
319
+ return results;
320
+ }
321
+ };
322
+
323
+ up.migrate.targetMacro = function(queryAttr, fixedResultAttrs, callback) {
324
+ return up.macro("[" + queryAttr + "]", function(link) {
325
+ var optionalTarget, resultAttrs;
326
+ resultAttrs = u.copy(fixedResultAttrs);
327
+ if (optionalTarget = link.getAttribute(queryAttr)) {
328
+ resultAttrs['up-target'] = optionalTarget;
329
+ } else {
330
+ resultAttrs['up-follow'] = '';
331
+ }
332
+ e.setMissingAttrs(link, resultAttrs);
333
+ link.removeAttribute(queryAttr);
334
+ return typeof callback === "function" ? callback() : void 0;
335
+ });
336
+ };
337
+
303
338
  }).call(this);
304
339
 
305
340
  /***
@@ -538,6 +573,11 @@ Returns the first descendant element matching the given selector.
538
573
  up.migrate.renamedProperty(up.feedback.config, 'navs', 'navSelectors');
539
574
 
540
575
  }).call(this);
576
+
577
+ /***
578
+ @module up.link
579
+ */
580
+
541
581
  (function() {
542
582
  up.migrate.parseFollowOptions = function(parser) {
543
583
  parser.string('flavor');
@@ -549,6 +589,42 @@ Returns the first descendant element matching the given selector.
549
589
  return parser.boolean('restoreScroll');
550
590
  };
551
591
 
592
+
593
+ /***
594
+ [Follows](/up.follow) this link as fast as possible.
595
+
596
+ This is done by:
597
+
598
+ - [Following the link through AJAX](/a-up-follow) instead of a full page load
599
+ - [Preloading the link's destination URL](/a-up-preload)
600
+ - [Triggering the link on `mousedown`](/a-up-instant) instead of on `click`
601
+
602
+ \#\#\# Example
603
+
604
+ Use `[up-dash]` like this:
605
+
606
+ <a href="/users" up-dash=".main">User list</a>
607
+
608
+ This is shorthand for:
609
+
610
+ <a href="/users" up-target=".main" up-instant up-preload>User list</a>
611
+
612
+ @selector a[up-dash]
613
+ @param [up-dash='body']
614
+ The CSS selector to replace
615
+
616
+ 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)).
617
+ @deprecated
618
+ To accelerate all links use `up.link.config.instantSelectors` and `up.link.config.preloadSelectors`.
619
+ */
620
+
621
+ up.migrate.targetMacro('up-dash', {
622
+ 'up-preload': '',
623
+ 'up-instant': ''
624
+ }, function() {
625
+ return up.migrate.deprecated('a[up-dash]', 'up.link.config.instantSelectors or up.link.config.preloadSelectors');
626
+ });
627
+
552
628
  }).call(this);
553
629
 
554
630
  /***
@@ -826,10 +902,10 @@ Returns the first descendant element matching the given selector.
826
902
  @param {string} up-modal
827
903
  The CSS selector that will be extracted from the response and displayed in a modal dialog.
828
904
  @deprecated
829
- Use `a[up-layer=modal]` instead.
905
+ Use `a[up-layer="new modal"]` instead.
830
906
  */
831
907
 
832
- up.link.targetMacro('up-modal', {
908
+ up.migrate.targetMacro('up-modal', {
833
909
  'up-layer': 'new modal'
834
910
  }, function() {
835
911
  return up.migrate.deprecated('a[up-modal]', 'a[up-layer="new modal"]');
@@ -846,16 +922,21 @@ Returns the first descendant element matching the given selector.
846
922
  @param {string} up-drawer
847
923
  The CSS selector that will be extracted from the response and displayed in a modal dialog.
848
924
  @deprecated
849
- Use `a[up-layer=drawer]` instead.
925
+ Use `a[up-layer="new drawer"]` instead.
850
926
  */
851
927
 
852
- up.link.targetMacro('up-drawer', {
928
+ up.migrate.targetMacro('up-drawer', {
853
929
  'up-layer': 'new drawer'
854
930
  }, function() {
855
931
  return up.migrate.deprecated('a[up-drawer]', 'a[up-layer="new drawer"]');
856
932
  });
857
933
 
858
934
  }).call(this);
935
+
936
+ /***
937
+ @module up.layer
938
+ */
939
+
859
940
  (function() {
860
941
  var e, u;
861
942
 
@@ -1060,15 +1141,6 @@ This feature is now deprecated.
1060
1141
 
1061
1142
  up.migrate.renamedProperty(up.network.config, 'slowDelay', 'badResponseTime');
1062
1143
 
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
1144
  up.migrate.handleRequestOptions = function(options) {
1073
1145
  return up.migrate.fixKey(options, 'data', 'params');
1074
1146
  };
@@ -1081,11 +1153,13 @@ This feature is now deprecated.
1081
1153
 
1082
1154
  \#\#\# Example
1083
1155
 
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
- })
1156
+ ```
1157
+ up.ajax('/search', { params: { query: 'sunshine' } }).then(function(text) {
1158
+ console.log('The response text is %o', text)
1159
+ }).catch(function() {
1160
+ console.error('The request failed')
1161
+ })
1162
+ ```
1089
1163
 
1090
1164
  @function up.ajax
1091
1165
  @param {string} [url]
@@ -1124,6 +1198,13 @@ This feature is now deprecated.
1124
1198
  return up.cache.clear();
1125
1199
  };
1126
1200
 
1201
+ up.network.preload = function() {
1202
+ var args, ref;
1203
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1204
+ up.migrate.deprecated('up.proxy.preload(link)', 'up.link.preload(link)');
1205
+ return (ref = up.link).preload.apply(ref, args);
1206
+ };
1207
+
1127
1208
 
1128
1209
  /***
1129
1210
  @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 o;o=up.util,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(n,u,p){return up.macro("["+n+"]",function(t){var r,a;return a=o.copy(u),(r=t.getAttribute(n))?a["up-target"]=r:a["up-follow"]="",e.setMissingAttrs(t,a),t.removeAttribute(n),"function"==typeof p?p():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.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=[].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-rc7"
8
+ version: "2.0.0"
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,6 +2590,7 @@ 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
2593
+ @param {Element} element
2524
2594
  @stable
2525
2595
  */
2526
2596
  show = function(element) {
@@ -2559,8 +2629,10 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
2559
2629
  @param {Element} element
2560
2630
  The element for which to add or remove the class.
2561
2631
  @param {string} className
2562
- A boolean value to determine whether the class should be added or removed.
2563
- @param {string} state
2632
+ The class which should be added or removed.
2633
+ @param {Boolean} [newPresent]
2634
+ Pass `true` to add the class to the element or `false` to remove it.
2635
+
2564
2636
  If omitted, the class will be added if missing and removed if present.
2565
2637
  @stable
2566
2638
  */
@@ -2909,6 +2981,15 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
2909
2981
  }
2910
2982
  };
2911
2983
 
2984
+ /***
2985
+ @function up.element.classSelector
2986
+ @internal
2987
+ */
2988
+ classSelector = function(klass) {
2989
+ klass = klass.replace(/:/g, '\\:');
2990
+ return "." + klass;
2991
+ };
2992
+
2912
2993
  /***
2913
2994
  Always creates a full document with a <html> root, even if the given `html`
2914
2995
  is only a fragment.
@@ -3442,6 +3523,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
3442
3523
  affix: affix,
3443
3524
  toSelector: toSelector,
3444
3525
  idSelector: idSelector,
3526
+ classSelector: classSelector,
3445
3527
  isSingleton: isSingleton,
3446
3528
  isSingletonSelector: isSingletonSelector,
3447
3529
  attributeSelector: attributeSelector,
@@ -4986,7 +5068,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
4986
5068
  };
4987
5069
 
4988
5070
  CompilerPass.prototype.runCompiler = function(compiler) {
4989
- var i, j, keepValue, len, len1, match, matches, results, value;
5071
+ var base, i, len, match, matches;
4990
5072
  matches = this.select(compiler.selector);
4991
5073
  if (!matches.length) {
4992
5074
  return;
@@ -5002,15 +5084,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
5002
5084
  this.compileOneElement(compiler, match);
5003
5085
  }
5004
5086
  }
5005
- if (keepValue = compiler.keep) {
5006
- value = u.isString(keepValue) ? keepValue : '';
5007
- results = [];
5008
- for (j = 0, len1 = matches.length; j < len1; j++) {
5009
- match = matches[j];
5010
- results.push(match.setAttribute('up-keep', value));
5011
- }
5012
- return results;
5013
- }
5087
+ return typeof (base = up.migrate).postCompile === "function" ? base.postCompile(matches, compiler) : void 0;
5014
5088
  };
5015
5089
 
5016
5090
  CompilerPass.prototype.compileOneElement = function(compiler, element) {
@@ -6231,8 +6305,12 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6231
6305
  /***
6232
6306
  Each layer has an `up.Layer` instance.
6233
6307
 
6234
- Most functions in the `up.layer` (lowercase) package interact with the [current layer](/up.layer.current).
6235
- 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.
6236
6314
 
6237
6315
  @class up.Layer
6238
6316
  */
@@ -6259,66 +6337,46 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6259
6337
 
6260
6338
 
6261
6339
  /***
6262
- This layer's mode which governs its appearance and behavior.
6263
-
6264
- Available layer modes are:
6340
+ Whether fragment updates within this layer can affect browser history and window title.
6265
6341
 
6266
- - `'root'`
6267
- - `'modal'`
6268
- - `'popup'`
6269
- - `'drawer'`
6270
- - `'cover'`
6342
+ If a layer does not have visible history, its desendant layers cannot have history either.
6271
6343
 
6272
- @property up.Layer#mode
6273
- @param {string} mode
6344
+ @property up.Layer#historyVisible
6345
+ @param {boolean} historyVisible
6274
6346
  @stable
6275
6347
  */
6276
6348
 
6277
6349
 
6278
6350
  /***
6279
- Whether fragment updates within this layer can affect browser history and window title.
6351
+ This layer's mode which governs its appearance and behavior.
6280
6352
 
6281
- @property up.Layer#historyVisible
6282
- @param {boolean} historyVisible
6353
+ @see layer-terminology
6354
+
6355
+ @property up.Layer#mode
6356
+ @param {string} mode
6357
+ @stable
6283
6358
  */
6284
6359
 
6285
6360
 
6286
6361
  /***
6287
- This layer's context object.
6288
-
6289
- Think of *context* as [session storage](/https://makandracards.com/makandra/32865), but specific to a [layer](/up.layer)
6290
- rather than specific to an entire browser tab.
6291
-
6292
- You may access the context object's properties like a regular JavaScript object.
6362
+ This layer's [context](/context).
6293
6363
 
6294
6364
  \#\#\# Example
6295
6365
 
6366
+ You may access the context properties like a regular JavaScript object.
6367
+
6296
6368
  ```js
6297
6369
  let layer = up.layer.current
6298
6370
  layer.context.message = 'Please select a contact'
6299
6371
  console.log(layer.context) // logs "{ message: 'Please select a contact' }"
6300
6372
  ```
6301
6373
 
6302
- \#\#\# Accessing the context from the server
6303
-
6304
- The context is is sent as an `X-Up-Context` header along with every
6305
- [request](/up.request) to the server. The server may also update the updating
6306
- layer's context by including an `X-Up-Context` header in its response.
6307
-
6308
6374
  @property up.Layer#context
6309
6375
  @param {Object} context
6310
- @stable
6311
- */
6312
-
6313
-
6314
- /***
6315
- Whether fragment updates within this layer will affect [browser history](/up.history).
6316
-
6317
- If a layer does not have visible history, its desendant layers cannot have history either.
6376
+ The context object.
6318
6377
 
6319
- @property up.Layer#historyVisible
6320
- @param {boolean} historyVisible
6321
- @stable
6378
+ If no context has been set an empty object is returned.
6379
+ @experimental
6322
6380
  */
6323
6381
 
6324
6382
  Layer.prototype.keys = function() {
@@ -6377,7 +6435,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6377
6435
  [Closes this overlay](/closing-overlays) with an accepting intent,
6378
6436
  e.g. when a change was confirmed or when a value was selected.
6379
6437
 
6380
- 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.
6381
6439
 
6382
6440
  @function up.Layer#accept
6383
6441
  @param {any} [value]
@@ -6415,7 +6473,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6415
6473
 
6416
6474
 
6417
6475
  /***
6418
- [Closes this overlay](/closing-overlays) without an accepting intent,
6476
+ [Closes this overlay](/closing-overlays) *without* an accepting intent,
6419
6477
  e.g. when a "Cancel" button was clicked.
6420
6478
 
6421
6479
  To close an overlay with an accepting intent, use `up.Layer#accept()` instead.
@@ -6490,7 +6548,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6490
6548
  /***
6491
6549
  Returns whether this layer is the [root layer](/up.layer.root).
6492
6550
 
6493
- @function up.Layer#isFront
6551
+ @function up.Layer#isRoot
6494
6552
  @return {boolean}
6495
6553
  @stable
6496
6554
  */
@@ -6571,7 +6629,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6571
6629
 
6572
6630
  Returns `undefined` if this layer has not opened a child layer.
6573
6631
 
6574
- 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
6575
6633
  first dismiss the existing child before replacing it with the new child.
6576
6634
 
6577
6635
  @property up.Layer#child
@@ -6587,6 +6645,10 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6587
6645
  /***
6588
6646
  Returns an array of this layer's ancestor layers.
6589
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
+
6590
6652
  @property up.Layer#ancestors
6591
6653
  @return {Array<up.Layer>} ancestors
6592
6654
  @stable
@@ -6602,6 +6664,10 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6602
6664
 
6603
6665
  Descendant layers are all layers that visually overlay this layer.
6604
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
+
6605
6671
  @property up.Layer#descendants
6606
6672
  @return {Array<up.Layer>} descendants
6607
6673
  @stable
@@ -6661,7 +6727,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6661
6727
 
6662
6728
 
6663
6729
  /***
6664
- 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
6665
6731
  on an element [contained](/up.Layer.prototype.contains) by this layer.
6666
6732
 
6667
6733
  This will ignore events emitted on elements in [descendant](/up.Layer.prototype.descendants) overlays,
@@ -6698,27 +6764,43 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6698
6764
  up.follow(overlayLink) // listener is not called
6699
6765
 
6700
6766
  @function up.Layer#on
6767
+
6701
6768
  @param {string} types
6702
6769
  A space-separated list of event types to bind to.
6703
- @param {string} [selector]
6770
+
6771
+ @param {string|Function(): string} [selector]
6704
6772
  The selector of an element on which the event must be triggered.
6705
6773
 
6706
6774
  Omit the selector to listen to all events of the given type, regardless
6707
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
+
6708
6781
  @param {boolean} [options.passive=false]
6709
6782
  Whether to register a [passive event listener](https://developers.google.com/web/updates/2016/06/passive-event-listeners).
6710
6783
 
6711
6784
  A passive event listener may not call `event.preventDefault()`.
6712
6785
  This in particular may improve the frame rate when registering
6713
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
+
6714
6794
  @param {Function(event, [element], [data])} listener
6715
6795
  The listener function that should be called.
6716
6796
 
6717
6797
  The function takes the affected element as the second argument.
6718
6798
  If the element has an [`up-data`](/up-data) attribute, its value is parsed as JSON
6719
6799
  and passed as a third argument.
6800
+
6720
6801
  @return {Function()}
6721
6802
  A function that unbinds the event listeners when called.
6803
+
6722
6804
  @stable
6723
6805
  */
6724
6806
 
@@ -6733,13 +6815,12 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6733
6815
  Unbinds an event listener previously bound with `up.Layer#on()`.
6734
6816
 
6735
6817
  @function up.Layer#off
6736
- @param {Element|jQuery} [element=document]
6737
6818
  @param {string} events
6738
- @param {string} [selector]
6819
+ @param {string|Function(): string} [selector]
6739
6820
  @param {Function(event, [element], [data])} listener
6740
6821
  The listener function to unbind.
6741
6822
 
6742
- 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
6743
6824
  that was passed to `up.Layer#on()` earlier.
6744
6825
  @stable
6745
6826
  */
@@ -6911,9 +6992,9 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
6911
6992
  /***
6912
6993
  This layer's location URL.
6913
6994
 
6914
- 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
6915
6997
  the browser's address bar will show the location of an ancestor layer.
6916
- This property will return the URL the layer would use if it had visible history.
6917
6998
 
6918
6999
  When this layer opens a child layer with visible history, the browser URL will change to the child
6919
7000
  layer's location. When the child layer is closed, this layer's location will be restored.
@@ -7236,7 +7317,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
7236
7317
  If the destruction is animated, the callback will run after the animation has finished.
7237
7318
  @return {Promise}
7238
7319
  A resolved promise.
7239
- @private
7320
+ @internal
7240
7321
  */
7241
7322
 
7242
7323
  Overlay.prototype.destroyElements = function(options) {
@@ -7375,6 +7456,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
7375
7456
  /***
7376
7457
  @function up.Layer.OverlayWithViewport#openNow
7377
7458
  @param {Element} options.content
7459
+ @internal
7378
7460
  */
7379
7461
 
7380
7462
  OverlayWithViewport.prototype.createElements = function(content) {
@@ -8888,6 +8970,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
8888
8970
  @param {string} name
8889
8971
  @return {any}
8890
8972
  The value of the param with the given name.
8973
+ @internal
8891
8974
  */
8892
8975
 
8893
8976
  Params.prototype.getFirst = function(name) {
@@ -8906,6 +8989,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
8906
8989
  @param {string} name
8907
8990
  @return {Array}
8908
8991
  An array of all values with the given name.
8992
+ @internal
8909
8993
  */
8910
8994
 
8911
8995
  Params.prototype.getAll = function(name) {
@@ -9253,7 +9337,15 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9253
9337
 
9254
9338
 
9255
9339
  /***
9256
- 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
+ ```
9257
9349
 
9258
9350
  @class up.RenderResult
9259
9351
  */
@@ -9304,17 +9396,18 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9304
9396
 
9305
9397
 
9306
9398
  /***
9307
- Instances of `up.Request` normalizes properties of an [`AJAX request`](/up.request)
9308
- such as the requested URL, form parameters and HTTP method.
9399
+ A normalized description of an [HTTP request](`up.request()`).
9309
9400
 
9310
9401
  You can queue a request using the `up.request()` method:
9311
9402
 
9312
- let request = up.request('/foo')
9313
- console.log(request.url)
9403
+ ```js
9404
+ let request = up.request('/foo')
9405
+ console.log(request.url)
9314
9406
 
9315
- // A request object is also a promise for its response
9316
- let response = await request
9317
- 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
+ ```
9318
9411
 
9319
9412
  @class up.Request
9320
9413
  */
@@ -9341,6 +9434,23 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9341
9434
  */
9342
9435
 
9343
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
+
9344
9454
  /***
9345
9455
  [Parameters](/up.Params) that should be sent as the request's payload.
9346
9456
 
@@ -9351,7 +9461,9 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9351
9461
 
9352
9462
 
9353
9463
  /***
9354
- 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.
9355
9467
 
9356
9468
  @property up.Request#target
9357
9469
  @param {string} target
@@ -9360,7 +9472,10 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9360
9472
 
9361
9473
 
9362
9474
  /***
9363
- 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.
9364
9479
 
9365
9480
  @property up.Request#failTarget
9366
9481
  @param {string} failTarget
@@ -9371,7 +9486,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9371
9486
  /***
9372
9487
  An object of additional HTTP headers.
9373
9488
 
9374
- 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.
9375
9490
  See `up.protocol` and `up.network.config.metaKeys` for details.
9376
9491
 
9377
9492
  @property up.Request#headers
@@ -9407,25 +9522,71 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9407
9522
 
9408
9523
 
9409
9524
  /***
9410
- 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.
9411
9528
 
9412
9529
  @property up.Request#context
9413
9530
  @param {Object} context
9414
- @stable
9531
+ @experimental
9415
9532
  */
9416
9533
 
9417
9534
 
9418
9535
  /***
9419
- 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.
9420
9539
 
9421
9540
  @property up.Request#failContext
9422
9541
  @param {Object} failContext
9423
- @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
9424
9583
  */
9425
9584
 
9426
9585
 
9427
9586
  /***
9428
- 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.
9429
9590
 
9430
9591
  @property up.Request#mode
9431
9592
  @param {string} mode
@@ -9434,7 +9595,9 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9434
9595
 
9435
9596
 
9436
9597
  /***
9437
- 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.
9438
9601
 
9439
9602
  @property up.Request#failMode
9440
9603
  @param {string} failMode
@@ -9443,7 +9606,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9443
9606
 
9444
9607
 
9445
9608
  /***
9446
- TODO: Docs
9609
+ The format in which the [request params](/up.Layer.prototype.params) will be encoded.
9447
9610
 
9448
9611
  @property up.Request#contentType
9449
9612
  @param {string} contentType
@@ -9452,13 +9615,22 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9452
9615
 
9453
9616
 
9454
9617
  /***
9455
- 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.
9456
9621
 
9457
9622
  @property up.Request#payload
9458
9623
  @param {string} payload
9459
9624
  @stable
9460
9625
  */
9461
9626
 
9627
+
9628
+ /***
9629
+ @property up.Request#preload
9630
+ @param {boolean} preload
9631
+ @experimental
9632
+ */
9633
+
9462
9634
  Request.prototype.keys = function() {
9463
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'];
9464
9636
  };
@@ -9514,7 +9686,8 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9514
9686
  Request.prototype.normalizeForCaching = function() {
9515
9687
  this.method = u.normalizeMethod(this.method);
9516
9688
  this.extractHashFromURL();
9517
- return this.transferParamsToURL();
9689
+ this.transferParamsToURL();
9690
+ return this.url = u.normalizeURL(this.url);
9518
9691
  };
9519
9692
 
9520
9693
  Request.prototype.evictExpensiveAttrs = function() {
@@ -9601,6 +9774,37 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
9601
9774
  });
9602
9775
  };
9603
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
+
9604
9808
  Request.prototype.loadPage = function() {
9605
9809
  up.network.abort();
9606
9810
  return new up.Request.FormRenderer(this).buildAndSubmit();
@@ -10180,7 +10384,7 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10180
10384
 
10181
10385
 
10182
10386
  /***
10183
- Instances of `up.Response` describe the server response to an [`AJAX request`](/up.request).
10387
+ A response to an [HTTP request](`up.request()`).
10184
10388
 
10185
10389
  \#\#\# Example
10186
10390
 
@@ -10292,6 +10496,14 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10292
10496
  @experimental
10293
10497
  */
10294
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
+
10295
10507
  Response.prototype.keys = function() {
10296
10508
  return ['method', 'url', 'text', 'status', 'request', 'xhr', 'target', 'title', 'acceptLayer', 'dismissLayer', 'eventPlans', 'context', 'clearCache', 'headers'];
10297
10509
  };
@@ -10838,7 +11050,8 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10838
11050
 
10839
11051
  }).call(this);
10840
11052
  (function() {
10841
- var e, u;
11053
+ var e, u,
11054
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
10842
11055
 
10843
11056
  u = up.util;
10844
11057
 
@@ -10846,6 +11059,8 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
10846
11059
 
10847
11060
  up.Tether = (function() {
10848
11061
  function Tether(options) {
11062
+ this.sync = bind(this.sync, this);
11063
+ this.scheduleSync = bind(this.scheduleSync, this);
10849
11064
  var base;
10850
11065
  if (typeof (base = up.migrate).handleTetherOptions === "function") {
10851
11066
  base.handleTetherOptions(options);
@@ -11147,37 +11362,26 @@ It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_ob
11147
11362
  Events
11148
11363
  ======
11149
11364
 
11150
- This module contains functions to [build](/up.event.build), [dispatch](/up.emit) and [listen to](/up.on) DOM events.
11365
+ This module contains functions to [emit](/up.emit) and [observe](/up.on) DOM events.
11151
11366
 
11152
- While the browser also ships with functions like [`Element#dispatchEvent()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent)
11153
- and [`Element#addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to
11154
- work with DOM events, you will find the functions in this module to be more convenient and feature-rich.
11367
+ While the browser also has built-in functions to work with events,
11368
+ you will find Unpoly's functions to be very concise and feature-rich.
11155
11369
 
11156
11370
  ## Events emitted by Unpoly
11157
11371
 
11158
- Most Unpoly interactions emit DOM events that are prefixed with `up:`.
11159
-
11160
- ```javascript
11161
- document.addEventListener('up:modal:opened', (event) => {
11162
- console.log('A new modal has just opened!')
11163
- })
11164
- ```
11165
-
11166
- Events often have both present and past forms. For example, `up:layer:open` is emitted before an overlay starts to open.
11167
- `up:layer:opened` is emitted when the overlay has appeared in the DOM tree.
11372
+ Most Unpoly features emit events that are prefixed with `up:`.
11168
11373
 
11169
- \#\#\# Preventing events
11374
+ Unpoly's own events are documented in their respective modules, for example:
11170
11375
 
11171
- You can prevent most present form events by calling `preventDefault()`:
11376
+ | Event | Module |
11377
+ |-----------------------|--------------------|
11378
+ | `up:link:follow` | `up.link` |
11379
+ | `up:form:submit` | `up.form` |
11380
+ | `up:layer:open` | `up.layer` |
11381
+ | `up:request:late` | `up.network` |
11172
11382
 
11173
- ```javascript
11174
- document.addEventListener('up:modal:open', (event) => {
11175
- if (event.url == '/evil') {
11176
- // Prevent the modal from opening
11177
- event.preventDefault()
11178
- }
11179
- })
11180
- ```
11383
+ @see up.on
11384
+ @see up.emit
11181
11385
 
11182
11386
  @module up.event
11183
11387
  */
@@ -11317,12 +11521,16 @@ document.addEventListener('up:modal:open', (event) => {
11317
11521
  Multiple event types may be passed as either a space-separated string
11318
11522
  or as an array of types.
11319
11523
 
11320
- @param {string} [selector]
11524
+ @param {string|Function():string} [selector]
11321
11525
  The selector of an element on which the event must be triggered.
11322
11526
 
11323
11527
  Omit the selector to listen to all events of the given type, regardless
11324
11528
  of the event target.
11325
11529
 
11530
+ If the selector is not known in advance you may also pass a function
11531
+ that returns the selector. The function is evaluated every time
11532
+ an event with the given type is observed.
11533
+
11326
11534
  @param {boolean} [options.passive=false]
11327
11535
  Whether to register a [passive event listener](https://developers.google.com/web/updates/2016/06/passive-event-listeners).
11328
11536
 
@@ -11333,7 +11541,7 @@ document.addEventListener('up:modal:open', (event) => {
11333
11541
  @param {boolean} [options.once=true]
11334
11542
  Whether the listener should run at most once.
11335
11543
 
11336
- If `true` the listener will automatically be removed from the element
11544
+ If `true` the listener will automatically be unbound
11337
11545
  after the first invocation.
11338
11546
 
11339
11547
  @param {Function(event, [element], [data])} listener
@@ -11424,12 +11632,12 @@ document.addEventListener('up:modal:open', (event) => {
11424
11632
 
11425
11633
  @function up.off
11426
11634
  @param {Element|jQuery} [element=document]
11427
- @param {string} events
11635
+ @param {string|Function(): string} events
11428
11636
  @param {string} [selector]
11429
11637
  @param {Function(event, [element], [data])} listener
11430
11638
  The listener function to unbind.
11431
11639
 
11432
- Note that you must pass a reference to the exact same listener function
11640
+ Note that you must pass a reference to the same function reference
11433
11641
  that was passed to `up.on()` earlier.
11434
11642
  @stable
11435
11643
  */
@@ -11680,8 +11888,12 @@ document.addEventListener('up:modal:open', (event) => {
11680
11888
 
11681
11889
  This hyperlink will emit an `user:select` event when clicked:
11682
11890
 
11683
- ```
11684
- <a href='/users/5" up-emit='user:select' up-emit-props='{ "id": 5, "firstName": "Alice" }'>Alice</a>
11891
+ ```html
11892
+ <a href='/users/5'
11893
+ up-emit='user:select'
11894
+ up-emit-props='{ "id": 5, "firstName": "Alice" }'>
11895
+ Alice
11896
+ </a>
11685
11897
 
11686
11898
  <script>
11687
11899
  up.on('a', 'user:select', function(event) {
@@ -11696,6 +11908,7 @@ document.addEventListener('up:modal:open', (event) => {
11696
11908
  The type of the event to be emitted.
11697
11909
  @param [up-emit-props='{}']
11698
11910
  The event properties, serialized as JSON.
11911
+ @stable
11699
11912
  */
11700
11913
  executeEmitAttr = function(event, element) {
11701
11914
  var eventProps, eventType, forkedEvent;
@@ -11764,7 +11977,7 @@ There are existing implementations for various web frameworks:
11764
11977
  - [Roda](https://github.com/adam12/roda-unpoly)
11765
11978
  - [Rack](https://github.com/adam12/rack-unpoly) (Sinatra, Padrino, Hanami, Cuba, ...)
11766
11979
  - [Phoenix](https://elixirforum.com/t/unpoly-a-framework-like-turbolinks/3614/15) (Elixir)
11767
- - [PHP](https://github.com/adam12/rack-unpoly) (Symfony, Laravel, Stack)
11980
+ - [PHP](https://github.com/webstronauts/php-unpoly) (Symfony, Laravel, Stack)
11768
11981
 
11769
11982
  @module up.protocol
11770
11983
  */
@@ -11987,68 +12200,35 @@ There are existing implementations for various web frameworks:
11987
12200
  The timestamp must be explicitely set by the user as an `[up-time]` attribute on the fragment.
11988
12201
  It should indicate the time when the fragment's underlying data was last changed.
11989
12202
 
11990
- Its value is the number of seconds elapsed since the [Unix epoch](https://en.wikipedia.org/wiki/Unix_time).
11991
-
11992
- If no timestamp is known, Unpoly will send a value of zero (`X-Up-Reload-From-Time: 0`).
11993
-
11994
- \#\#\# Example
12203
+ See `[up-time]` for a detailed example.
11995
12204
 
11996
- You may timestamp your fragments with an `[up-time]` attribute to indicate when the underlying data
11997
- was last changed. For instance, when the last message in a list was received from December 24th, 1:51:46 PM UTC:
12205
+ \#\#\# Format
11998
12206
 
11999
- ```html
12000
- <div class="messages" up-time="1608730818">
12001
- ...
12002
- </div>
12003
- ```
12207
+ The time is encoded is the number of seconds elapsed since the [Unix epoch](https://en.wikipedia.org/wiki/Unix_time).
12004
12208
 
12005
- When reloading the `.messages` fragment, Unpoly will echo that timestamp in an `X-Up-Reload-From-Time` header:
12209
+ For instance, a modification date of December 23th, 1:40:18 PM UTC would produce the following header:
12006
12210
 
12007
12211
  ```http
12212
+ X-Up-Target: .unread-count
12008
12213
  X-Up-Reload-From-Time: 1608730818
12009
12214
  ```
12010
12215
 
12011
- \#\# Cheap polling responses
12216
+ If no timestamp is known, Unpoly will send a value of zero (`X-Up-Reload-From-Time: 0`).
12012
12217
 
12013
- A use case for the `X-Up-Reload-From-Time` header is to avoid rendering unchanged content
12014
- while [polling](/up-poll).
12218
+ @header X-Up-Reload-From-Time
12219
+ @stable
12220
+ */
12221
+ contextFromXHR = function(xhr) {
12222
+ return extractHeader(xhr, 'context', JSON.parse);
12223
+ };
12224
+
12225
+ /***
12226
+ This request header contains the targeted layer's [context](/context), serialized as JSON.
12015
12227
 
12016
- The server can compare the time from the request with the time of the last data update.
12017
- If no more recent data is available, the server can [render nothing](/X-Up-Target):
12228
+ The user may choose to not send this header by configuring
12229
+ `up.network.config.requestMetaKeys`.
12018
12230
 
12019
- ```ruby
12020
- class MessagesController < ApplicationController
12021
-
12022
- def index
12023
- if up.reload_from_time == current_user.last_message_at
12024
- up.render_nothing
12025
- else
12026
- @messages = current_user.messages.order(time: :desc).to_a
12027
- render 'index'
12028
- end
12029
- end
12030
-
12031
- end
12032
- ```
12033
-
12034
- Only rendering when needed saves <b>CPU time</b> on your server, which spends most of its response time rendering HTML.
12035
-
12036
- This also reduces the <b>bandwidth cost</b> for a request/response exchange to **~1 KB**.
12037
-
12038
- @header X-Up-Reload-From-Time
12039
- @stable
12040
- */
12041
- contextFromXHR = function(xhr) {
12042
- return extractHeader(xhr, 'context', JSON.parse);
12043
- };
12044
-
12045
- /***
12046
- This request header contains the targeted layer's [context](/up.context), serialized as JSON.
12047
-
12048
- The user may choose to not send this header by configuring
12049
- `up.network.config.requestMetaKeys`.
12050
-
12051
- \#\#\# Example
12231
+ \#\#\# Example
12052
12232
 
12053
12233
  ```http
12054
12234
  X-Up-Context: { "lives": 3 }
@@ -12084,11 +12264,11 @@ There are existing implementations for various web frameworks:
12084
12264
  the request was in flight will get overridden by the server-provided context.
12085
12265
 
12086
12266
  @header X-Up-Context
12087
- @stable
12267
+ @experimental
12088
12268
  */
12089
12269
 
12090
12270
  /***
12091
- This request header contains the [context](/up.context) of the layer
12271
+ This request header contains the [context](/context) of the layer
12092
12272
  targeted for a failed fragment update, serialized as JSON.
12093
12273
 
12094
12274
  A fragment update is considered *failed* if the server responds with a
@@ -12107,7 +12287,7 @@ There are existing implementations for various web frameworks:
12107
12287
  ```
12108
12288
 
12109
12289
  @header X-Up-Fail-Context
12110
- @stable
12290
+ @experimental
12111
12291
  */
12112
12292
 
12113
12293
  /***
@@ -12267,7 +12447,7 @@ There are existing implementations for various web frameworks:
12267
12447
  the response's HTML content.
12268
12448
 
12269
12449
  The header value is the acceptance value serialized as a JSON object.
12270
- To accept an overlay without value, set the header value to `null`.
12450
+ To accept an overlay without value, set the header value to the string `null`.
12271
12451
 
12272
12452
  \#\#\# Example
12273
12453
 
@@ -12313,7 +12493,7 @@ There are existing implementations for various web frameworks:
12313
12493
  the response's HTML content.
12314
12494
 
12315
12495
  The header value is the dismissal value serialized as a JSON object.
12316
- To accept an overlay without value, set the header value to `null`.
12496
+ To accept an overlay without value, set the header value to the string `null`.
12317
12497
 
12318
12498
  \#\#\# Example
12319
12499
 
@@ -12425,10 +12605,12 @@ There are existing implementations for various web frameworks:
12425
12605
  Configures strings used in the optional [server protocol](/up.protocol).
12426
12606
 
12427
12607
  @property up.protocol.config
12608
+
12428
12609
  @param {string} [config.csrfHeader='X-CSRF-Token']
12429
12610
  The name of the HTTP header that will include the
12430
12611
  [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern)
12431
12612
  for AJAX requests.
12613
+
12432
12614
  @param {string|Function(): string} [config.csrfParam]
12433
12615
  The `name` of the hidden `<input>` used for sending a
12434
12616
  [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern) when
@@ -12440,7 +12622,10 @@ There are existing implementations for various web frameworks:
12440
12622
 
12441
12623
  Defaults to the `content` attribute of a `<meta>` tag named `csrf-param`:
12442
12624
 
12443
- <meta name="csrf-param" content="authenticity_token" />
12625
+ ```html
12626
+ <meta name="csrf-param" content="authenticity_token" />
12627
+ ```
12628
+
12444
12629
  @param {string|Function(): string} [config.csrfToken]
12445
12630
  The [CSRF token](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern)
12446
12631
  to send for unsafe requests. The token will be sent as either a HTTP header (for AJAX requests)
@@ -12451,7 +12636,10 @@ There are existing implementations for various web frameworks:
12451
12636
 
12452
12637
  Defaults to the `content` attribute of a `<meta>` tag named `csrf-token`:
12453
12638
 
12454
- <meta name='csrf-token' content='secret12345'>
12639
+ ```
12640
+ <meta name='csrf-token' content='secret12345'>
12641
+ ```
12642
+
12455
12643
  @param {string} [config.methodParam='_method']
12456
12644
  The name of request parameter containing the original request method when Unpoly needs to wrap
12457
12645
  the method.
@@ -12530,13 +12718,14 @@ There are existing implementations for various web frameworks:
12530
12718
  Logging
12531
12719
  =======
12532
12720
 
12533
- Unpoly can print debugging information to the developer console, e.g.:
12721
+ Unpoly can print debugging information to the [browser console](https://developer.chrome.com/docs/devtools/console/), e.g.:
12534
12722
 
12535
12723
  - Which [events](/up.event) are called
12536
12724
  - When we're [making requests to the network](/up.request)
12537
12725
  - Which [compilers](/up.syntax) are applied to which elements
12538
12726
 
12539
- You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12727
+ @see up.log.enable
12728
+ @see up.log.disable
12540
12729
 
12541
12730
  @module up.log
12542
12731
  */
@@ -12559,11 +12748,14 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12559
12748
  Debugging information includes which elements are being [compiled](/up.syntax)
12560
12749
  and which [events](/up.event) are being emitted.
12561
12750
  Note that errors will always be printed, regardless of this setting.
12562
- @internal
12751
+ @param {boolean} [options.banner=true]
12752
+ Print the Unpoly banner to the developer console.
12753
+ @stable
12563
12754
  */
12564
12755
  config = new up.Config(function() {
12565
12756
  return {
12566
- enabled: sessionStore.get('enabled')
12757
+ enabled: sessionStore.get('enabled'),
12758
+ banner: true
12567
12759
  };
12568
12760
  });
12569
12761
  reset = function() {
@@ -12621,6 +12813,9 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12621
12813
  };
12622
12814
  printBanner = function() {
12623
12815
  var color, logo, text;
12816
+ if (!config.banner) {
12817
+ return;
12818
+ }
12624
12819
  logo = " __ _____ ___ ___ / /_ __\n" + ("/ // / _ \\/ _ \\/ _ \\/ / // / " + up.version + "\n") + "\\___/_//_/ .__/\\___/_/\\_. / \n" + " / / / /\n\n";
12625
12820
  text = "";
12626
12821
  if (!up.migrate.loaded) {
@@ -12638,7 +12833,7 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12638
12833
  return console.log(logo + text);
12639
12834
  }
12640
12835
  };
12641
- up.on('up:framework:boot', printBanner);
12836
+ up.on('up:app:boot', printBanner);
12642
12837
  up.on('up:framework:reset', reset);
12643
12838
  setEnabled = function(value) {
12644
12839
  sessionStore.set('enabled', value);
@@ -12646,7 +12841,7 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12646
12841
  };
12647
12842
 
12648
12843
  /***
12649
- Makes future Unpoly events print vast amounts of debugging information to the developer console.
12844
+ Starts printing debugging information to the developer console.
12650
12845
 
12651
12846
  Debugging information includes which elements are being [compiled](/up.syntax)
12652
12847
  and which [events](/up.event) are being emitted.
@@ -12661,7 +12856,7 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12661
12856
  };
12662
12857
 
12663
12858
  /***
12664
- Prevents future Unpoly events from printing vast amounts of debugging information to the developer console.
12859
+ Stops printing debugging information to the developer console.
12665
12860
 
12666
12861
  Errors will still be printed, even with logging disabled.
12667
12862
 
@@ -12703,24 +12898,26 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12703
12898
  };
12704
12899
 
12705
12900
  /***
12706
- * Registers an empty rejection handler in case the given promise
12707
- * rejects with an AbortError or a failed up.Response.
12708
- *
12709
- * This prevents browsers from printing "Uncaught (in promise)" to the error
12710
- * console when the promise is rejected.
12711
- *
12712
- * This is helpful for event handlers where it is clear that no rejection
12713
- * handler will be registered:
12714
- *
12715
- * up.on('submit', 'form[up-target]', (event, form) => {
12716
- * promise = up.submit(form)
12717
- * up.util.muteRejection(promise)
12718
- * })
12719
- *
12720
- * @function up.log.muteUncriticalRejection
12721
- * @param {Promise} promise
12722
- * @return {Promise}
12723
- * @internal
12901
+ Registers an empty rejection handler in case the given promise
12902
+ rejects with an AbortError or a failed up.Response.
12903
+
12904
+ This prevents browsers from printing "Uncaught (in promise)" to the error
12905
+ console when the promise is rejected.
12906
+
12907
+ This is helpful for event handlers where it is clear that no rejection
12908
+ handler will be registered:
12909
+
12910
+ ```js
12911
+ up.on('submit', 'form[up-target]', (event, form) => {
12912
+ promise = up.submit(form)
12913
+ up.util.muteRejection(promise)
12914
+ })
12915
+ ```
12916
+
12917
+ @function up.log.muteUncriticalRejection
12918
+ @param {Promise} promise
12919
+ @return {Promise}
12920
+ @internal
12724
12921
  */
12725
12922
  muteUncriticalRejection = function(promise) {
12726
12923
  return promise["catch"](function(error) {
@@ -12756,20 +12953,11 @@ You can activate logging by calling [`up.log.enable()`](/up.log.enable).
12756
12953
  Custom JavaScript
12757
12954
  =================
12758
12955
 
12759
- Every app needs a way to pair JavaScript snippets with certain HTML elements,
12760
- in order to integrate libraries or implement custom behavior.
12956
+ The `up.syntax` package lets you pair HTML elements with JavaScript behavior.
12761
12957
 
12762
- Unpoly lets you organize your JavaScript snippets using [compilers](/up.compiler).
12763
-
12764
- For instance, to activate the [Masonry](http://masonry.desandro.com/) library for every element
12765
- with a `grid` class, use this compiler:
12766
-
12767
- up.compiler('.grid', function(element) {
12768
- new Masonry(element, { itemSelector: '.grid--item' })
12769
- })
12770
-
12771
- The compiler function will be called on matching elements when the page loads
12772
- or when a matching fragment is [inserted via AJAX](/up.link) later.
12958
+ @see up.compiler
12959
+ @see [up-data]
12960
+ @see up.macro
12773
12961
 
12774
12962
  @module up.syntax
12775
12963
  */
@@ -12804,14 +12992,17 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
12804
12992
  Use compilers to activate your custom Javascript behavior on matching
12805
12993
  elements.
12806
12994
 
12807
- You should migrate your [`DOMContentLoaded`](https://api.jquery.com/ready/)
12995
+ You should migrate your [`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event)
12808
12996
  callbacks to compilers. This will make sure they run both at page load and
12809
12997
  when a new fragment is inserted later.
12810
- It will also organize your JavaScript snippets by selector of affected elements.
12998
+ See [Making JavaScripts work with fragment updates](/legacy-scripts) for advice
12999
+ on migrating legacy scripts.
13000
+
13001
+ It will also organize your JavaScript snippets by selector.
12811
13002
 
12812
13003
  \#\#\# Example
12813
13004
 
12814
- This jQuery compiler will insert the current time into a
13005
+ This compiler will insert the current time into a
12815
13006
  `<div class='current-time'></div>`:
12816
13007
 
12817
13008
  ```js
@@ -12872,55 +13063,34 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
12872
13063
 
12873
13064
  An alternative way to register a destructor function is `up.destructor()`.
12874
13065
 
12875
- \#\#\# Attaching structured data
13066
+ \#\#\# Passing parameters to a compiler
12876
13067
 
12877
- In case you want to attach structured data to the event you're observing,
12878
- you can serialize the data to JSON and put it into an `[up-data]` attribute.
12879
- For instance, a container for a [Google Map](https://developers.google.com/maps/documentation/javascript/tutorial)
12880
- might attach the location and names of its marker pins:
13068
+ Use the `[up-data]` attribute to attach structured data to a DOM element.
13069
+ The data will be parsed and passed to your compiler function.
12881
13070
 
12882
- ```html
12883
- <div class='google-map' up-data='[
12884
- { "lat": 48.36, "lng": 10.99, "title": "Friedberg" },
12885
- { "lat": 48.75, "lng": 11.45, "title": "Ingolstadt" }
12886
- ]'></div>
12887
- ```
12888
-
12889
- The JSON will be parsed and handed to your compiler as a second argument:
12890
-
12891
- ```js
12892
- up.compiler('.google-map', function(element, pins) {
12893
- var map = new google.maps.Map(element)
13071
+ Alternatively your compiler may access attributes for the compiled element
13072
+ via the standard [`Element#getAttribute()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute)
13073
+ method.
12894
13074
 
12895
- pins.forEach(function(pin) {
12896
- var position = new google.maps.LatLng(pin.lat, pin.lng)
12897
- new google.maps.Marker({
12898
- position: position,
12899
- map: map,
12900
- title: pin.title
12901
- })
12902
- })
12903
- })
12904
- ```
13075
+ Unpoly also provides utility functions to read an element attribute and
13076
+ cast it to a given type:
12905
13077
 
12906
- @see legacy-scripts
13078
+ - `up.element.booleanAttr(element, attr)`
13079
+ - `up.element.numberAttr(element, attr)`
13080
+ - `up.element.jsonAttr(element, attr)`
12907
13081
 
12908
13082
  @function up.compiler
12909
13083
  @param {string} selector
12910
13084
  The selector to match.
12911
13085
  @param {number} [options.priority=0]
12912
13086
  The priority of this compiler.
13087
+
12913
13088
  Compilers with a higher priority are run first.
12914
13089
  Two compilers with the same priority are run in the order they were registered.
12915
13090
  @param {boolean} [options.batch=false]
12916
13091
  If set to `true` and a fragment insertion contains multiple
12917
- elements matching the selector, `compiler` is only called once
12918
- with a jQuery collection containing all matching elements.
12919
- @param {boolean} [options.keep=false]
12920
- If set to `true` compiled fragment will be [persisted](/up-keep) during
12921
- fragment updates.
12922
-
12923
- This has the same effect as setting an `up-keep` attribute on the element.
13092
+ elements matching `selector`, the `compiler` function is only called once
13093
+ with all these elements.
12924
13094
  @param {Function(element, data)} compiler
12925
13095
  The function to call when a matching element is inserted.
12926
13096
 
@@ -12957,10 +13127,12 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
12957
13127
  This jQuery compiler will insert the current time into a
12958
13128
  `<div class='current-time'></div>`:
12959
13129
 
12960
- up.$compiler('.current-time', function($element) {
12961
- var now = new Date()
12962
- $element.text(now.toString())
12963
- })
13130
+ ```js
13131
+ up.$compiler('.current-time', function($element) {
13132
+ var now = new Date()
13133
+ $element.text(now.toString())
13134
+ })
13135
+ ```
12964
13136
 
12965
13137
  @function up.$compiler
12966
13138
  @param {string} selector
@@ -12984,33 +13156,40 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
12984
13156
  /***
12985
13157
  Registers a [compiler](/up.compiler) that is run before all other compilers.
12986
13158
 
12987
- Use `up.macro()` to register a compiler that sets multiple Unpoly attributes.
13159
+ A macro lets you set UJS attributes that will be compiled afterwards.
13160
+
13161
+ If you want default attributes for *every* link and form, consider customizing your
13162
+ [navigation options](/navigation).
12988
13163
 
12989
13164
  \#\#\# Example
12990
13165
 
12991
13166
  You will sometimes find yourself setting the same combination of UJS attributes again and again:
12992
13167
 
12993
- <a href="/page1" up-target=".content" up-transition="cross-fade" up-duration="300">Page 1</a>
12994
- <a href="/page2" up-target=".content" up-transition="cross-fade" up-duration="300">Page 2</a>
12995
- <a href="/page3" up-target=".content" up-transition="cross-fade" up-duration="300">Page 3</a>
13168
+ ```html
13169
+ <a href="/page1" up-layer="new modal" up-class="warning" up-animation="shake">Page 1</a>
13170
+ <a href="/page1" up-layer="new modal" up-class="warning" up-animation="shake">Page 1</a>
13171
+ <a href="/page1" up-layer="new modal" up-class="warning" up-animation="shake">Page 1</a>
13172
+ ```
12996
13173
 
12997
- We would much rather define a new `[content-link]` attribute that let's us
13174
+ We would much rather define a new `[smooth-link]` attribute that let's us
12998
13175
  write the same links like this:
12999
13176
 
13000
- <a href="/page1" content-link>Page 1</a>
13001
- <a href="/page2" content-link>Page 2</a>
13002
- <a href="/page3" content-link>Page 3</a>
13177
+ ```html
13178
+ <a href="/page1" smooth-link>Page 1</a>
13179
+ <a href="/page2" smooth-link>Page 2</a>
13180
+ <a href="/page3" smooth-link>Page 3</a>
13181
+ ```
13003
13182
 
13004
13183
  We can define the `[content-link]` attribute by registering a macro that
13005
13184
  sets the `[up-target]`, `[up-transition]` and `[up-duration]` attributes for us:
13006
13185
 
13007
- up.macro('[content-link]', function(link) {
13008
- link.setAttribute('up-target', '.content')
13009
- link.setAttribute('up-transition', 'cross-fade')
13010
- link.setAttribute('up-duration', '300')
13011
- })
13012
-
13013
- Examples for built-in macros are [`a[up-dash]`](/a-up-dash) and [`[up-expand]`](/up-expand).
13186
+ ```
13187
+ up.macro('[smooth-link]', function(link) {
13188
+ link.setAttribute('up-target', '.content')
13189
+ link.setAttribute('up-transition', 'cross-fade')
13190
+ link.setAttribute('up-duration', '300')
13191
+ })
13192
+ ```
13014
13193
 
13015
13194
  @function up.macro
13016
13195
  @param {string} selector
@@ -13043,13 +13222,15 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13043
13222
 
13044
13223
  \#\#\# Example
13045
13224
 
13046
- up.$macro('[content-link]', function($link) {
13047
- $link.attr(
13048
- 'up-target': '.content',
13049
- 'up-transition': 'cross-fade',
13050
- 'up-duration':'300'
13051
- )
13052
- })
13225
+ ```js
13226
+ up.$macro('[content-link]', function($link) {
13227
+ $link.attr(
13228
+ 'up-target': '.content',
13229
+ 'up-transition': 'cross-fade',
13230
+ 'up-duration':'300'
13231
+ )
13232
+ })
13233
+ ```
13053
13234
 
13054
13235
  @function up.$macro
13055
13236
  @param {string} selector
@@ -13111,6 +13292,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13111
13292
 
13112
13293
  /***
13113
13294
  Applies all compilers on the given element and its descendants.
13295
+
13114
13296
  Unlike [`up.hello()`](/up.hello), this doesn't emit any events.
13115
13297
 
13116
13298
  @function up.syntax.compile
@@ -13139,8 +13321,8 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13139
13321
  })
13140
13322
  ```
13141
13323
 
13142
- An alternative way to register a destructor function is to `return`
13143
- it from your compiler function.
13324
+ An alternative way to register a destructor function is to
13325
+ [`return` it from your compiler function](/up.compiler#cleaning-up-after-yourself).
13144
13326
 
13145
13327
  @function up.destructor
13146
13328
  @param {Element} element
@@ -13164,6 +13346,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13164
13346
 
13165
13347
  /***
13166
13348
  Runs any destructor on the given fragment and its descendants in the same layer.
13349
+
13167
13350
  Unlike [`up.destroy()`](/up.destroy), this does not emit any events
13168
13351
  and does not remove the element from the DOM.
13169
13352
 
@@ -13182,20 +13365,23 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13182
13365
  };
13183
13366
 
13184
13367
  /***
13185
- Checks if the given element has an [`up-data`](/up-data) attribute.
13186
- If yes, parses the attribute value as JSON and returns the parsed object.
13368
+ Returns the given element's `[up-data]`, parsed as a JavaScript object.
13187
13369
 
13188
- Returns `undefined` if the element has no `up-data` attribute.
13370
+ Returns `undefined` if the element has no `[up-data]` attribute.
13189
13371
 
13190
13372
  \#\#\# Example
13191
13373
 
13192
13374
  You have an element with JSON data serialized into an `up-data` attribute:
13193
13375
 
13194
- <span class='person' up-data='{ "age": 18, "name": "Bob" }'>Bob</span>
13376
+ ```html
13377
+ <span class='person' up-data='{ "age": 18, "name": "Bob" }'>Bob</span>
13378
+ ```
13195
13379
 
13196
13380
  Calling `up.syntax.data()` will deserialize the JSON string into a JavaScript object:
13197
13381
 
13198
- up.syntax.data('.person') // returns { age: 18, name: 'Bob' }
13382
+ ```js
13383
+ up.syntax.data('.person') // returns { age: 18, name: 'Bob' }
13384
+ ```
13199
13385
 
13200
13386
  @function up.data
13201
13387
  @param {string|Element|jQuery} element
@@ -13208,39 +13394,49 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13208
13394
  */
13209
13395
 
13210
13396
  /***
13211
- If an element with an `up-data` attribute enters the DOM,
13397
+ Attaches structured data to an element, to be consumed by a compiler.
13398
+
13399
+ If an element with an `[up-data]` attribute enters the DOM,
13212
13400
  Unpoly will parse the JSON and pass the resulting object to any matching
13213
- [`up.compiler()`](/up.compiler) handlers.
13401
+ [`up.compiler()`](/up.compiler) functions.
13402
+
13403
+ \#\#\# Example
13214
13404
 
13215
13405
  For instance, a container for a [Google Map](https://developers.google.com/maps/documentation/javascript/tutorial)
13216
13406
  might attach the location and names of its marker pins:
13217
13407
 
13218
- <div class='google-map' up-data='[
13219
- { "lat": 48.36, "lng": 10.99, "title": "Friedberg" },
13220
- { "lat": 48.75, "lng": 11.45, "title": "Ingolstadt" }
13221
- ]'></div>
13408
+ ```html
13409
+ <div class='google-map' up-data='[
13410
+ { "lat": 48.36, "lng": 10.99, "title": "Friedberg" },
13411
+ { "lat": 48.75, "lng": 11.45, "title": "Ingolstadt" }
13412
+ ]'></div>
13413
+ ```
13222
13414
 
13223
13415
  The JSON will be parsed and handed to your compiler as a second argument:
13224
13416
 
13225
- up.compiler('.google-map', function(element, pins) {
13226
- var map = new google.maps.Map(element)
13227
- pins.forEach(function(pin) {
13228
- var position = new google.maps.LatLng(pin.lat, pin.lng)
13229
- new google.maps.Marker({
13230
- position: position,
13231
- map: map,
13232
- title: pin.title
13233
- })
13234
- })
13417
+ ```js
13418
+ up.compiler('.google-map', function(element, pins) {
13419
+ var map = new google.maps.Map(element)
13420
+ pins.forEach(function(pin) {
13421
+ var position = new google.maps.LatLng(pin.lat, pin.lng)
13422
+ new google.maps.Marker({
13423
+ position: position,
13424
+ map: map,
13425
+ title: pin.title
13235
13426
  })
13427
+ })
13428
+ })
13429
+ ```
13236
13430
 
13237
13431
  Similarly, when an event is triggered on an element annotated with
13238
13432
  [`up-data`], the parsed object will be passed to any matching
13239
13433
  [`up.on()`](/up.on) handlers.
13240
13434
 
13241
- up.on('click', '.google-map', function(event, element, pins) {
13242
- console.log("There are %d pins on the clicked map", pins.length)
13243
- })
13435
+ ```js
13436
+ up.on('click', '.google-map', function(event, element, pins) {
13437
+ console.log("There are %d pins on the clicked map", pins.length)
13438
+ })
13439
+ ```
13244
13440
 
13245
13441
  @selector [up-data]
13246
13442
  @param up-data
@@ -13293,9 +13489,10 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
13293
13489
  History
13294
13490
  ========
13295
13491
 
13296
- In an Unpoly app, every page has an URL.
13492
+ The `up.history` module helps you work with the browser history.
13297
13493
 
13298
- [Fragment updates](/up.link) automatically update the URL.
13494
+ @see up.history.location
13495
+ @see up:location:changed
13299
13496
 
13300
13497
  @module up.history
13301
13498
  */
@@ -13320,7 +13517,7 @@ In an Unpoly app, every page has an URL.
13320
13517
  Defines whether [fragment updates](/up.render) will update the browser's current URL.
13321
13518
 
13322
13519
  If set to `false` Unpoly will never change the browser URL.
13323
- @param {boolean} [config.restoreScroll=true]
13520
+ @param {boolean} [config.enabled=true]
13324
13521
  Whether to restore the known scroll positions
13325
13522
  when the user goes back or forward in history.
13326
13523
  @stable
@@ -13429,7 +13626,7 @@ In an Unpoly app, every page has an URL.
13429
13626
  address bar with the given URL.
13430
13627
 
13431
13628
  When the user restores the new history entry later,
13432
- Unpoly will replace the document body with the body from that URL.
13629
+ Unpoly will replace a selector from `up.history.config.restoreTargets` with the body from that URL.
13433
13630
 
13434
13631
  Note that [fragment navigation](/navigation) will automatically update the
13435
13632
  browser's location bar for you.
@@ -13463,7 +13660,7 @@ In an Unpoly app, every page has an URL.
13463
13660
 
13464
13661
  When a [layer](/up.layer) has no [visible history](/up.Layer.prototype.historyVisible), following a link
13465
13662
  will not cause the browser's address bar to be updated. In this case no `up:location:changed` event will be emitted.
13466
- There will however be an `up:layer:location:changed` event be emitted.
13663
+ However, a `up:layer:location:changed` will be emitted even if the address bar did not change.
13467
13664
 
13468
13665
  @event up:location:changed
13469
13666
  @param {string} event.url
@@ -13536,9 +13733,11 @@ In an Unpoly app, every page has an URL.
13536
13733
  register = function() {
13537
13734
  window.history.scrollRestoration = 'manual';
13538
13735
  window.addEventListener('popstate', pop);
13539
- return replace(currentLocation(), {
13540
- event: false
13541
- });
13736
+ if (up.protocol.initialRequestMethod() === 'GET') {
13737
+ return replace(currentLocation(), {
13738
+ event: false
13739
+ });
13740
+ }
13542
13741
  };
13543
13742
  if (typeof jasmine !== "undefined" && jasmine !== null) {
13544
13743
  return register();
@@ -13601,31 +13800,48 @@ In an Unpoly app, every page has an URL.
13601
13800
  })();
13602
13801
 
13603
13802
  }).call(this);
13803
+ (function() {
13804
+ var e, u,
13805
+ slice = [].slice;
13604
13806
 
13605
- /***
13606
- Fragment update API
13607
- ===================
13608
-
13609
- The `up.fragment` module exposes a high-level Javascript API to [update](/up.replace) or
13610
- [destroy](/up.destroy) page fragments.
13611
-
13612
- Fragments are [compiled](/up.compiler) elements that can be updated from a server URL.
13613
- They also exist on a layer (page, modal, popup).
13807
+ u = up.util;
13614
13808
 
13615
- Most of Unpoly's functionality (like [fragment links](/up.link) or [modals](/up.modal))
13616
- is built from `up.fragment` functions. You may use them to extend Unpoly from your
13617
- [custom Javascript](/up.syntax).
13809
+ e = up.element;
13618
13810
 
13619
- @module up.fragment
13620
- */
13621
13811
 
13622
- (function() {
13623
- var slice = [].slice;
13812
+ /***
13813
+ Fragment API
13814
+ ===========
13815
+
13816
+ The `up.fragment` module offers a high-level JavaScript API to work with DOM elements.
13817
+
13818
+ A fragment is an element with some additional properties that are useful in the context of
13819
+ a server-rendered web application:
13820
+
13821
+ - Fragments are [identified by a CSS selector](/up.fragment.toTarget), like a `.class` or `#id`.
13822
+ - Fragments are usually updated by a [link](/a-up-follow) for [form](/form-up-submits) that targets their selector.
13823
+ When the server renders HTML with a matching element, the fragment is swapped with a new version.
13824
+ - As fragments enter the page they are automatically [compiled](/up.compiler) to activate JavaScript behavior.
13825
+ - Fragment changes may be [animated](/up.motion).
13826
+ - Fragments are placed on a [layer](/up.layer) that is isolated from other layers.
13827
+ Unpoly features will only see or change fragments from the [current layer](/up.layer.current)
13828
+ unless you [explicitly target another layer](/layer-option).
13829
+ - Fragments [know the URL from where they were loaded](/up.source).
13830
+ They can be [reloaded](/up.reload) or [polled periodically](/up-polled).
13831
+
13832
+ For low-level DOM utilities that complement the browser's native API, see `up.element`.
13833
+
13834
+ @see up.render
13835
+ @see up.navigate
13836
+ @see up.destroy
13837
+ @see up.reload
13838
+ @see up.fragment.get
13839
+ @see up.hello
13840
+
13841
+ @module up.fragment
13842
+ */
13624
13843
 
13625
13844
  up.fragment = (function() {
13626
- 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;
13627
- u = up.util;
13628
- e = up.element;
13629
13845
 
13630
13846
  /***
13631
13847
  Configures defaults for fragment updates.
@@ -13671,7 +13887,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13671
13887
  The default configuration tries, in this order:
13672
13888
 
13673
13889
  - If the URL has a `#hash`, scroll to the hash.
13674
- - If updating a [main target](/main), reset scroll positions.
13890
+ - If updating a [main target](/up-main), reset scroll positions.
13675
13891
 
13676
13892
  @param {boolean|string|Function(Element)} [config.autoFocus]
13677
13893
  How to focus when updating a fragment with `{ focus: 'auto' }`.
@@ -13683,7 +13899,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13683
13899
  - Focus a `#hash` in the URL.
13684
13900
  - Focus an `[autofocus]` element in the new fragment.
13685
13901
  - If focus was lost with the old fragment, focus the new fragment.
13686
- - If updating a [main target](/main), focus the new fragment.
13902
+ - If updating a [main target](/up-main), focus the new fragment.
13687
13903
 
13688
13904
  @param {boolean} [config.runScripts=false]
13689
13905
  Whether to execute `<script>` tags in updated fragments.
@@ -13691,7 +13907,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13691
13907
  Scripts will load asynchronously, with no guarantee of execution order.
13692
13908
 
13693
13909
  If you set this to `true`, mind that the `<body>` element is a default
13694
- [main target](/main). If you are including your global application scripts
13910
+ [main target](/up-main). If you are including your global application scripts
13695
13911
  at the end of your `<body>`
13696
13912
  for performance reasons, swapping the `<body>` will re-execute these scripts.
13697
13913
  In that case you must configure a different main target that does not include
@@ -13699,6 +13915,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13699
13915
 
13700
13916
  @stable
13701
13917
  */
13918
+ 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;
13702
13919
  config = new up.Config(function() {
13703
13920
  return {
13704
13921
  badTargetClasses: [/^up-/],
@@ -13719,13 +13936,8 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13719
13936
  autoScroll: ['hash', 'layer-if-main']
13720
13937
  };
13721
13938
  });
13722
- Object.defineProperty(config, 'mainTargets', {
13723
- get: function() {
13724
- return up.layer.config.any.mainTargets;
13725
- },
13726
- set: function(value) {
13727
- return up.layer.config.any.mainTargets = value;
13728
- }
13939
+ u.delegate(config, 'mainTargets', function() {
13940
+ return up.layer.config.any;
13729
13941
  });
13730
13942
  reset = function() {
13731
13943
  return config.reset();
@@ -13779,6 +13991,74 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13779
13991
  return e.closestAttr(element, 'up-time') || '0';
13780
13992
  };
13781
13993
 
13994
+ /***
13995
+ Sets the time when the fragment's underlying data was last changed.
13996
+
13997
+ This can be used to avoid rendering unchanged HTML when [reloading](/up.reload)
13998
+ a fragment. This saves <b>CPU time</b> and reduces the <b>bandwidth cost</b> for a
13999
+ request/response exchange to **~1 KB**.
14000
+
14001
+ \#\# Example
14002
+
14003
+ Let's say we display a list of recent messages.
14004
+ We use the `[up-poll]` attribute to reload the `.messages` fragment every 30 seconds:
14005
+
14006
+ ```html
14007
+ <div class="messages" up-poll>
14008
+ ...
14009
+ </div>
14010
+ ```
14011
+
14012
+ The list is now always up to date. But most of the time there will not be new messages,
14013
+ and we waste resources sending the same unchanged HTML from the server.
14014
+
14015
+ We can improve this by setting an `[up-time]` attribute and the message list.
14016
+ The attribute value is the time of the most recent message.
14017
+
14018
+ The time is encoded as the number of seconds since [Unix epoch](https://en.wikipedia.org/wiki/Unix_time).
14019
+ When, for instance, the last message in a list was received from December 24th, 1:51:46 PM UTC,
14020
+ we use the following HTML:
14021
+
14022
+ ```html
14023
+ <div class="messages" up-time="1608730818" up-poll>
14024
+ ...
14025
+ </div>
14026
+ ```
14027
+
14028
+ When reloading Unpoly will echo the `[up-time]` timestamp in an `X-Up-Reload-From-Time` header:
14029
+
14030
+ ```http
14031
+ X-Up-Reload-From-Time: 1608730818
14032
+ ```
14033
+
14034
+ The server can compare the time from the request with the time of the last data update.
14035
+ If no more recent data is available, the server can render nothing and respond with
14036
+ an [`X-Up-Target: :none`](/X-Up-Target) header.
14037
+
14038
+ Here is an example with [unpoly-rails](https://unpoly.com/install/rails):
14039
+
14040
+ ```ruby
14041
+ class MessagesController < ApplicationController
14042
+
14043
+ def index
14044
+ if up.reload_from_time == current_user.last_message_at
14045
+ up.render_nothing
14046
+ else
14047
+ @messages = current_user.messages.order(time: :desc).to_a
14048
+ render 'index'
14049
+ end
14050
+ end
14051
+
14052
+ end
14053
+ ```
14054
+
14055
+ @selector [up-time]
14056
+ @param {string} up-time
14057
+ The number of seconds between the [Unix epoch](https://en.wikipedia.org/wiki/Unix_time).
14058
+ and the time when the element's underlying data was last changed.
14059
+ @experimental
14060
+ */
14061
+
13782
14062
  /***
13783
14063
  Sets this element's source URL for [reloading](/up.reload) and [polling](/up-poll)
13784
14064
 
@@ -13800,7 +14080,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13800
14080
  </div>
13801
14081
 
13802
14082
  @selector [up-source]
13803
- @param {String} up-source
14083
+ @param {string} up-source
13804
14084
  The URL from which to reload this element.
13805
14085
  @stable
13806
14086
  */
@@ -13810,7 +14090,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13810
14090
 
13811
14091
  The current and new elements must both match the same CSS selector.
13812
14092
  The selector is either given as `{ target }` option,
13813
- or a [main target](/main) is used as default.
14093
+ or a [main target](/up-main) is used as default.
13814
14094
 
13815
14095
  See the [fragment placement](/fragment-placement) selector for many examples for how you can target content.
13816
14096
 
@@ -13871,29 +14151,32 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13871
14151
 
13872
14152
  @function up.render
13873
14153
 
13874
- @param {string|Element|jQuery} [target]
14154
+ @param {string|Element|jQuery|Array<string>} [target]
13875
14155
  The CSS selector to update.
13876
14156
 
13877
- If omitted a [main target](/main) will be rendered.
14157
+ If omitted a [main target](/up-main) will be rendered.
13878
14158
 
13879
- You can also pass a DOM element or jQuery element here, in which case a selector
14159
+ You may also pass a DOM element or jQuery element here, in which case a selector
13880
14160
  will be [inferred from the element attributes](/up.fragment.toTarget). The given element
13881
14161
  will also be used as [`{ origin }`](#options.origin) for the fragment update.
13882
14162
 
14163
+ You may also pass an array of selector alternatives. The first selector
14164
+ matching in both old and new content will be used.
14165
+
13883
14166
  Instead of passing the target as the first argument, you may also pass it as
13884
14167
  a [´{ target }`](#options.target) option..
13885
14168
 
13886
- @param {string|Element|jQuery} [options.target]
14169
+ @param {string|Element|jQuery|Array<string>} [options.target]
13887
14170
  The CSS selector to update.
13888
14171
 
13889
- If omitted a [main target](/main) will be rendered.
14172
+ See documentation for the [`target`](#target) parameter.
13890
14173
 
13891
14174
  @param {string|boolean} [options.fallback=false]
13892
14175
  Specifies behavior if the [target selector](/up.render#options.target) is missing from the current page or the server response.
13893
14176
 
13894
14177
  If set to a CSS selector string, Unpoly will attempt to replace that selector instead.
13895
14178
 
13896
- If set to `true` Unpoly will attempt to replace a [main target](/main) instead.
14179
+ If set to `true` Unpoly will attempt to replace a [main target](/up-main) instead.
13897
14180
 
13898
14181
  If set to `false` Unpoly will immediately reject the render promise.
13899
14182
 
@@ -13973,12 +14256,12 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
13973
14256
 
13974
14257
  If set to `'auto'` history will be updated if the `{ target }` matches
13975
14258
  a selector in `up.fragment.config.autoHistoryTargets`. By default this contains all
13976
- [main targets](/main).
14259
+ [main targets](/up-main).
13977
14260
 
13978
14261
  If set to `false`, the history will remain unchanged.
13979
14262
 
13980
14263
  [Overlays](/up.layer) will only change the browser URL and window title if the overlay
13981
- has [visible history](/up.layer.historyVisible), even with `{ history: true }`.
14264
+ has [visible history](/up.layer.historyVisible), even when `{ history: true }` is passed.
13982
14265
 
13983
14266
  @param {string} [options.title]
13984
14267
  An explicit document title to use after rendering.
@@ -14029,11 +14312,12 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14029
14312
  Also see [`up.request({ cache })`](/up.request#options.cache).
14030
14313
 
14031
14314
  @param {boolean|string} [options.clearCache]
14032
- Whether existing [cache](/up.cache) entries will be cleared with this request.
14315
+ Whether existing [cache](/up.cache) entries will be [cleared](/up.cache.clear) with this request.
14033
14316
 
14034
- By default a non-GET request will clear the entire cache.
14035
14317
  You may also pass a [URL pattern](/url-patterns) to only clear matching requests.
14036
14318
 
14319
+ By default a non-GET request will clear the entire cache.
14320
+
14037
14321
  Also see [`up.request({ clearCache })`](/up.request#options.clearCache) and `up.network.config.clearCache`.
14038
14322
 
14039
14323
  @param {Element|jQuery} [options.origin]
@@ -14058,7 +14342,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14058
14342
  This is only relevant when updating a layer that is not the [frontmost layer](/up.layer.front).
14059
14343
 
14060
14344
  @param {Object} [options.context]
14061
- An object that will be merged into the [context](/up.context) of the current layer once the fragment is rendered.
14345
+ An object that will be merged into the [context](/context) of the current layer once the fragment is rendered.
14062
14346
 
14063
14347
  @param {boolean} [options.keep=true]
14064
14348
  Whether [`[up-keep]`](/up-keep) elements will be preserved in the updated fragment.
@@ -14162,7 +14446,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14162
14446
  @param {string|Element|jQuery} [target]
14163
14447
  The CSS selector to update.
14164
14448
 
14165
- If omitted a [main target](/main) will be rendered.
14449
+ If omitted a [main target](/up-main) will be rendered.
14166
14450
 
14167
14451
  You can also pass a DOM element or jQuery element here, in which case a selector
14168
14452
  will be [inferred from the element attributes](/up.fragment.target). The given element
@@ -14192,17 +14476,19 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14192
14476
  an entirely different page layout (like a maintenance page or fatal server error)
14193
14477
  which should be open with a full page load:
14194
14478
 
14195
- up.on('up:fragment:loaded', (event) => {
14196
- let isMaintenancePage = event.response.getHeader('X-Maintenance')
14479
+ ```js
14480
+ up.on('up:fragment:loaded', (event) => {
14481
+ let isMaintenancePage = event.response.getHeader('X-Maintenance')
14197
14482
 
14198
- if (isMaintenancePage) {
14199
- // Prevent the fragment update and don't update browser history
14200
- event.preventDefault()
14483
+ if (isMaintenancePage) {
14484
+ // Prevent the fragment update and don't update browser history
14485
+ event.preventDefault()
14201
14486
 
14202
- // Make a full page load for the same request.
14203
- event.request.loadPage()
14204
- }
14205
- })
14487
+ // Make a full page load for the same request.
14488
+ event.request.loadPage()
14489
+ }
14490
+ })
14491
+ ```
14206
14492
 
14207
14493
  Instead of preventing the update, listeners may also access the `event.renderOptions` object
14208
14494
  to mutate options to the `up.render()` call that will process the server response.
@@ -14216,6 +14502,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14216
14502
  The server response.
14217
14503
  @param {Object} event.renderOptions
14218
14504
  Options for the `up.render()` call that will process the server response.
14505
+ @stable
14219
14506
  */
14220
14507
 
14221
14508
  /***
@@ -14601,7 +14888,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14601
14888
  - The [`up.element.all()`](/up.element.get) function simply returns the all elements matching a selector
14602
14889
  without further filtering.
14603
14890
 
14604
- @function up.fragment.get
14891
+ @function up.fragment.all
14605
14892
 
14606
14893
  @param {Element|jQuery} [root=document]
14607
14894
  The root element for the search. Only the root's children will be matched.
@@ -14836,7 +15123,8 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14836
15123
 
14837
15124
  \#\#\# Skipping updates when nothing changed
14838
15125
 
14839
- TODO: Document [up-time] and X-Up-Reload-From-Time (currently both documented in `X-Up-Reload-From-Time`).
15126
+ You may use the `[up-time]` attribute to avoid rendering unchanged HTML when reloading
15127
+ a fragment. See `[up-time]` for a detailed example.
14840
15128
 
14841
15129
  @function up.reload
14842
15130
  @param {string|Element|jQuery} [target]
@@ -14914,11 +15202,12 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14914
15202
 
14915
15203
  \#\#\# Example
14916
15204
 
14917
- element = document.createElement('span')
14918
- element.className = 'klass'
14919
- selector = up.fragment.toTarget(element) // returns '.klass'
15205
+ ```js
15206
+ element = up.element.createFromHTML('<span class="klass">...</span>')
15207
+ selector = up.fragment.toTarget(element) // returns '.klass'
15208
+ ```
14920
15209
 
14921
- @function up.element.toTarget
15210
+ @function up.fragment.toTarget
14922
15211
  @param {string|Element|jQuery}
14923
15212
  The element for which to create a selector.
14924
15213
  @stable
@@ -14941,7 +15230,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
14941
15230
  selector = '';
14942
15231
  for (i = 0, len = goodClasses.length; i < len; i++) {
14943
15232
  klass = goodClasses[i];
14944
- selector += "." + klass;
15233
+ selector += e.classSelector(klass);
14945
15234
  }
14946
15235
  return selector;
14947
15236
  } else {
@@ -15091,10 +15380,13 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
15091
15380
  When no other render target is given, Unpoly will try to find and replace a main target.
15092
15381
 
15093
15382
  In most app layouts the main target should match the primary content area.
15094
- The default main targets are the HTML5 [`<main>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main) element,
15095
- any element with an `[up-main]` attribute and the current layer's
15096
- [topmost swappable element](/main). You may configure main target selectors
15097
- in `up.fragment.config.mainTargets`.
15383
+ The default main targets are:
15384
+
15385
+ - any element with an `[up-main]` attribute
15386
+ - the HTML5 [`<main>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main) element
15387
+ - the current layer's [topmost swappable element](/layer)
15388
+
15389
+ You may configure main target selectors in `up.fragment.config.mainTargets`.
15098
15390
 
15099
15391
  \#\#\# Example
15100
15392
 
@@ -15106,6 +15398,86 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
15106
15398
  @experimental
15107
15399
  */
15108
15400
 
15401
+ /***
15402
+ Updates this element when no other render target is given.
15403
+
15404
+ \#\#\# Example
15405
+
15406
+ Many links simply replace the main content element in your application layout.
15407
+
15408
+ Unpoly lets you mark this elements as a default target using the `[up-main]` attribute:
15409
+
15410
+ ```html
15411
+ <body>
15412
+ <div class="layout">
15413
+ <div class="layout--side">
15414
+ ...
15415
+ </div>
15416
+ <div class="layout--content" up-main>
15417
+ ...
15418
+ </div>
15419
+ </div>
15420
+ </body>
15421
+ ```
15422
+
15423
+ Once a main target is configured, you no longer need `[up-target]` in a link.\
15424
+ Use `[up-follow]` and the `[up-main]` element will be replaced:
15425
+
15426
+ ```html
15427
+ <a href="/foo" up-follow>...</a>
15428
+ ```
15429
+
15430
+ If you want to update something more specific, you can still use `[up-target]`:
15431
+
15432
+ ```html
15433
+ <a href="/foo" up-target=".profile">...</a>
15434
+ ```
15435
+
15436
+ Instead of assigning `[up-main]` you may also configure an existing selector in `up.fragment.config.mainTargets`:
15437
+
15438
+ ```js
15439
+ up.fragment.config.mainTargets.push('.layout--content')
15440
+ ```
15441
+
15442
+ Overlays can use different main targets
15443
+ ---------------------------------------
15444
+
15445
+ Overlays often use a different default selector, e.g. to exclude a navigation bar.
15446
+
15447
+ To define a different main target for an overlay, set the [layer mode](/layer-terminology) as the
15448
+ value of the `[up-main]` attribute:
15449
+
15450
+ ```html
15451
+ <body>
15452
+ <div class="layout" up-main="root">
15453
+ <div class="layout--side">
15454
+ ...
15455
+ </div>
15456
+ <div class="layout--content" up-main="modal">
15457
+ ...
15458
+ </div>
15459
+ </div>
15460
+ </body>
15461
+ ```
15462
+
15463
+ Instead of assigning `[up-main]` you may also configure layer-specific targets in `up.layer.config`:
15464
+
15465
+ ```js
15466
+ up.layer.config.popup.mainTargets.push('.menu') // for popup overlays
15467
+ up.layer.config.drawer.mainTargets.push('.menu') // for drawer overlays
15468
+ up.layer.config.overlay.mainTargets.push('.layout--content') // for all overlay modes
15469
+ ```
15470
+
15471
+ @selector [up-main]
15472
+ @param [up-main]
15473
+ A space-separated list of [layer modes](/layer-terminology) for which to use this main target.
15474
+
15475
+ Omit the attribute value to define a main target for *all* layer modes.
15476
+
15477
+ To use a different main target for all overlays (but not the root layer), set `[up-main=overlay]`.
15478
+ @stable
15479
+ */
15480
+
15109
15481
  /***
15110
15482
  To make a server request without changing a fragment, use the `:none` selector.
15111
15483
 
@@ -15150,7 +15522,7 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
15150
15522
  For the [root layer](/up.layer.root) it is the `<body>` element. For an overlay
15151
15523
  it is the target with which the overlay was opened with.
15152
15524
 
15153
- In canonical usage the topmost swappable element is often a [main element](/main).
15525
+ In canonical usage the topmost swappable element is often a [main element](/up-main).
15154
15526
 
15155
15527
  \#\#\# Example
15156
15528
 
@@ -15247,36 +15619,39 @@ is built from `up.fragment` functions. You may use them to extend Unpoly from yo
15247
15619
 
15248
15620
  up.visit = up.fragment.visit;
15249
15621
 
15622
+
15623
+ /***
15624
+ Returns the current [context](/context).
15625
+
15626
+ This is aliased as `up.layer.context`.
15627
+
15628
+ @property up.context
15629
+ @param {Object} context
15630
+ The context object.
15631
+
15632
+ If no context has been set an empty object is returned.
15633
+ @experimental
15634
+ */
15635
+
15636
+ u.delegate(up, 'context', function() {
15637
+ return up.layer.current;
15638
+ });
15639
+
15250
15640
  }).call(this);
15251
15641
 
15252
15642
  /***
15253
15643
  Scrolling viewports
15254
15644
  ===================
15255
15645
 
15256
- The `up.viewport` module controls the scroll position of scrollable containers ("viewports").
15646
+ The `up.viewport` module controls the scroll position and focus within scrollable containers ("viewports").
15257
15647
 
15258
15648
  The default viewport for any web application is the main document. An application may
15259
15649
  define additional viewports by giving the CSS property `{ overflow-y: scroll }` to any `<div>`.
15260
15650
 
15651
+ Also see documentation for the [scroll option](/scroll-option) and [focus option](focus-option).
15261
15652
 
15262
- \#\#\# Revealing new content
15263
-
15264
- When following a [link to a fragment](/a-up-follow) Unpoly will automatically
15265
- scroll the document's viewport to [reveal](/up.viewport) the updated content.
15266
-
15267
- You should [make Unpoly aware](/up.viewport.config#config.fixedTop) of fixed elements in your
15268
- layout, such as navigation bars or headers. Unpoly will respect these sticky
15269
- elements when [revealing updated fragments](/up.reveal).
15270
-
15271
- You should also [tell Unpoly](/up.viewport.config#config.viewportSelectors) when your application has more than one viewport,
15272
- so Unpoly can pick the right viewport to scroll for each fragment update.
15273
-
15274
-
15275
- \#\#\# Bootstrap integration
15276
-
15277
- When using Bootstrap integration (`unpoly-bootstrap3.js` and `unpoly-bootstrap3.css`)
15278
- Unpoly will automatically be aware of sticky Bootstrap components such as
15279
- [fixed navbar](https://getbootstrap.com/examples/navbar-fixed-top/).
15653
+ @see up.reveal
15654
+ @see [up-fixed=top]
15280
15655
 
15281
15656
  @module up.viewport
15282
15657
  */
@@ -15285,29 +15660,31 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15285
15660
  var slice = [].slice;
15286
15661
 
15287
15662
  up.viewport = (function() {
15288
- 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;
15663
+ 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;
15289
15664
  u = up.util;
15290
15665
  e = up.element;
15291
15666
  f = up.fragment;
15292
15667
 
15293
15668
  /***
15294
- Configures the application layout.
15669
+ Configures defaults for scrolling.
15295
15670
 
15296
15671
  @property up.viewport.config
15297
15672
  @param {Array} [config.viewportSelectors]
15298
- An array of CSS selectors that find viewports
15299
- (containers that scroll their contents).
15673
+ An array of CSS selectors that match viewports.
15300
15674
  @param {Array} [config.fixedTop]
15301
15675
  An array of CSS selectors that find elements fixed to the
15302
15676
  top edge of the screen (using `position: fixed`).
15677
+
15303
15678
  See [`[up-fixed="top"]`](/up-fixed-top) for details.
15304
15679
  @param {Array} [config.fixedBottom]
15305
- An array of CSS selectors that find elements fixed to the
15680
+ An array of CSS selectors that match elements fixed to the
15306
15681
  bottom edge of the screen (using `position: fixed`).
15682
+
15307
15683
  See [`[up-fixed="bottom"]`](/up-fixed-bottom) for details.
15308
15684
  @param {Array} [config.anchoredRight]
15309
15685
  An array of CSS selectors that find elements anchored to the
15310
15686
  right edge of the screen (using `right:0` with `position: fixed` or `position: absolute`).
15687
+
15311
15688
  See [`[up-anchored="right"]`](/up-anchored-right) for details.
15312
15689
  @param {number} [config.revealSnap]
15313
15690
  When [revealing](/up.reveal) elements, Unpoly will scroll an viewport
@@ -15421,19 +15798,9 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15421
15798
  };
15422
15799
 
15423
15800
  /***
15424
- Scroll's the given element's viewport so the first rows of the
15801
+ Scrolls the given element's viewport so the first rows of the
15425
15802
  element are visible for the user.
15426
15803
 
15427
- \#\#\# How Unpoly finds the viewport
15428
-
15429
- The viewport (the container that is going to be scrolled)
15430
- is the closest parent of the element that is either:
15431
-
15432
- - the currently open [modal](/up.modal)
15433
- - an element with the attribute `[up-viewport]`
15434
- - the `<body>` element
15435
- - an element matching the selector you have configured using `up.viewport.config.viewportSelectors.push('my-custom-selector')`
15436
-
15437
15804
  \#\#\# Fixed elements obstructing the viewport
15438
15805
 
15439
15806
  Many applications have a navigation bar fixed to the top or bottom,
@@ -15441,14 +15808,16 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15441
15808
 
15442
15809
  You can make `up.reveal()` aware of these fixed elements
15443
15810
  so it can scroll the viewport far enough so the revealed element is fully visible.
15444
- To make `up.reveal()` aware fixed elements you can either:
15811
+ To make `up.reveal()` aware of fixed elements you can either:
15445
15812
 
15446
15813
  - give the element an attribute [`up-fixed="top"`](/up-fixed-top) or [`up-fixed="bottom"`](up-fixed-bottom)
15447
15814
  - [configure default options](/up.viewport.config) for `fixedTop` or `fixedBottom`
15448
15815
 
15449
15816
  @function up.reveal
15817
+
15450
15818
  @param {string|Element|jQuery} element
15451
15819
  The element to reveal.
15820
+
15452
15821
  @param {number} [options.scrollSpeed=1]
15453
15822
  The speed of the scrolling motion when scrolling with `{ behavior: 'smooth' }`.
15454
15823
 
@@ -15456,6 +15825,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15456
15825
  [native smooth scrolling](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior).
15457
15826
 
15458
15827
  Defaults to `up.viewport.config.scrollSpeed`.
15828
+
15459
15829
  @param {string} [options.revealSnap]
15460
15830
  When the the revealed element would be closer to the viewport's top edge
15461
15831
  than this value, Unpoly will scroll the viewport to the top.
@@ -15463,35 +15833,40 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15463
15833
  Set to `0` to disable snapping.
15464
15834
 
15465
15835
  Defaults to `up.viewport.config.revealSnap`.
15836
+
15466
15837
  @param {string|Element|jQuery} [options.viewport]
15467
15838
  The scrolling element to scroll.
15468
15839
 
15469
15840
  Defaults to the [given element's viewport](/up.viewport.closest).
15841
+
15470
15842
  @param {boolean} [options.top]
15471
15843
  Whether to scroll the viewport so that the first element row aligns
15472
15844
  with the top edge of the viewport.
15473
15845
 
15474
15846
  Defaults to `up.viewport.config.revealTop`.
15847
+
15475
15848
  @param {string}[options.behavior='auto']
15476
15849
  When set to `'auto'`, this will immediately scroll to the new position.
15477
15850
 
15478
15851
  When set to `'smooth'`, this will scroll smoothly to the new position.
15852
+
15479
15853
  @param {number}[options.speed]
15480
15854
  The speed of the scrolling motion when scrolling with `{ behavior: 'smooth' }`.
15481
15855
 
15482
15856
  Defaults to `up.viewport.config.scrollSpeed`.
15857
+
15483
15858
  @param {number} [options.padding]
15484
15859
  The desired padding between the revealed element and the
15485
15860
  closest [viewport](/up.viewport) edge (in pixels).
15486
15861
 
15487
15862
  Defaults to `up.viewport.config.revealPadding`.
15863
+
15488
15864
  @param {number|boolean} [options.snap]
15489
15865
  Whether to snap to the top of the viewport if the new scroll position
15490
15866
  after revealing the element is close to the top edge.
15491
15867
 
15492
15868
  Defaults to `up.viewport.config.revealSnap`.
15493
- @param {boolean} [options.peel=true]
15494
- Whether to close overlays obscuring the layer of `element`.
15869
+
15495
15870
  @return {Promise}
15496
15871
  A promise that fulfills when the element is revealed.
15497
15872
 
@@ -15500,13 +15875,12 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15500
15875
 
15501
15876
  When the scrolling is not animated, the promise will fulfill
15502
15877
  in the next [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/).
15878
+
15503
15879
  @stable
15504
15880
  */
15505
15881
  reveal = function(element, options) {
15506
15882
  var motion;
15507
- options = u.options(options, {
15508
- peel: true
15509
- });
15883
+ options = u.options(options);
15510
15884
  element = f.get(element, options);
15511
15885
  if (!(options.layer = up.layer.get(element))) {
15512
15886
  return up.error.failed.async('Cannot reveal a detached element');
@@ -15519,7 +15893,19 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15519
15893
  };
15520
15894
 
15521
15895
  /***
15522
- TODO: Docs
15896
+ Focuses the given element.
15897
+
15898
+ Focusing an element will also [reveal](/up.reveal) it, unless `{ preventScroll: true }` is passed.
15899
+
15900
+ @function up.focus
15901
+
15902
+ @param {string|Element|jQuery} element
15903
+ The element to focus.
15904
+
15905
+ @param {[options.preventScroll=false]}
15906
+ Whether to prevent changes to the acroll position.
15907
+
15908
+ @experimental
15523
15909
  */
15524
15910
  doFocus = function(element, options) {
15525
15911
  var oldScrollTop, viewport;
@@ -15544,13 +15930,6 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15544
15930
  doFocus(element, options);
15545
15931
  return element === document.activeElement;
15546
15932
  };
15547
- autofocus = function(element, options) {
15548
- var autofocusElement;
15549
- if (autofocusElement = e.subtree(element, '[autofocus]')[0]) {
15550
- doDocus(autofocusElement, options);
15551
- return true;
15552
- }
15553
- };
15554
15933
  isNativelyFocusable = function(element) {
15555
15934
  return e.matches(element, 'a[href], button, textarea, input, select');
15556
15935
  };
@@ -15620,6 +15999,9 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15620
15999
  Returns a list of all the viewports contained within the
15621
16000
  given selector or element.
15622
16001
 
16002
+ If the given element is itself a viewport, the element is included
16003
+ in the returned list.
16004
+
15623
16005
  @function up.viewport.subtree
15624
16006
  @param {string|Element|jQuery} target
15625
16007
  @param {Object} options
@@ -15812,30 +16194,11 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
15812
16194
 
15813
16195
  The scroll positions will be associated with the current URL.
15814
16196
  They can later be restored by calling [`up.viewport.restoreScroll()`](/up.viewport.restoreScroll)
15815
- at the same URL, or by following a link with an [`[up-restore-scroll]`](/a-up-follow#up-restore-scroll)
16197
+ at the same URL, or by following a link with an [`[scroll="restore"]`](/a-up-follow#up-restore-scroll)
15816
16198
  attribute.
15817
16199
 
15818
- Unpoly automatically saves scroll positions before a [fragment update](/up.replace)
15819
- you will rarely need to call this function yourself.
15820
-
15821
- \#\#\# Examples
15822
-
15823
- Should you need to save the current scroll positions outside of a [fragment update](/up.replace),
15824
- you may call:
15825
-
15826
- up.viewport.saveScroll()
15827
-
15828
- Instead of saving the current scroll positions for the current URL, you may also pass another
15829
- url or vertical scroll positionsfor each viewport:
15830
-
15831
- up.viewport.saveScroll({
15832
- url: '/inbox',
15833
- tops: {
15834
- 'body': 0,
15835
- '.sidebar', 100,
15836
- '.main', 320
15837
- }
15838
- })
16200
+ Unpoly automatically saves scroll positions before [navigating](/navigation).
16201
+ You will rarely need to call this function yourself.
15839
16202
 
15840
16203
  @function up.viewport.saveScroll
15841
16204
  @param {string} [options.location]
@@ -16162,7 +16525,6 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
16162
16525
  absolutize: absolutize,
16163
16526
  focus: doFocus,
16164
16527
  tryFocus: tryFocus,
16165
- autofocus: autofocus,
16166
16528
  makeFocusable: makeFocusable
16167
16529
  });
16168
16530
  })();
@@ -16181,11 +16543,16 @@ Animation
16181
16543
 
16182
16544
  When you [update a page fragment](/up.link) you can animate the change.
16183
16545
 
16184
- Let's say you are using an [`up-follow`](/a-up-follow) link to update an element
16185
- with content from the server. You can add an attribute [`up-transition`](/a-up-follow#up-transition)
16186
- to smoothly fade out the old element while fading in the new element:
16546
+ You can add an attribute [`[up-transition]`](/a-up-transition) to your
16547
+ links or forms to smoothly fade out the old element while fading in the new element:
16187
16548
 
16188
- <a href="/users" up-target=".list" up-transition="cross-fade">Show users</a>
16549
+ ```html
16550
+ <a href="/users"
16551
+ up-target=".list"
16552
+ up-transition="cross-fade">
16553
+ Show users
16554
+ </a>
16555
+ ```
16189
16556
 
16190
16557
  \#\#\# Transitions vs. animations
16191
16558
 
@@ -16193,10 +16560,17 @@ When we morph between an old and a new element, we call it a *transition*.
16193
16560
  In contrast, when we animate a new element without simultaneously removing an
16194
16561
  old element, we call it an *animation*.
16195
16562
 
16196
- An example for an animation is opening a new dialog. We can animate the appearance
16197
- of the dialog by adding an [`[up-animation]`](/a-up-modal#up-animation) attribute to the opening link:
16563
+ An example for an animation is opening a new overlay. We can animate the appearance
16564
+ of the dialog by adding an [`[up-animation]`](/a-up-animation) attribute to the opening link:
16198
16565
 
16199
- <a href="/users" up-modal=".list" up-animation="move-from-top">Show users</a>
16566
+ ```html
16567
+ <a href="/users"
16568
+ up-target=".list"
16569
+ up-layer="new"
16570
+ up-animation="move-from-top">
16571
+ Show users
16572
+ </a>
16573
+ ```
16200
16574
 
16201
16575
  \#\#\# Which animations are available?
16202
16576
 
@@ -16206,12 +16580,16 @@ and [predefined animations](/up.animate#named-animations).
16206
16580
  You can define custom animations using `up.transition()` and
16207
16581
  `up.animation()`.
16208
16582
 
16583
+ @see a[up-transition]
16584
+ @see up.animation
16585
+ @see up.transition
16586
+
16209
16587
  @module up.motion
16210
16588
  */
16211
16589
 
16212
16590
  (function() {
16213
16591
  up.motion = (function() {
16214
- 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;
16592
+ 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;
16215
16593
  u = up.util;
16216
16594
  e = up.element;
16217
16595
  namedAnimations = {};
@@ -16229,9 +16607,12 @@ You can define custom animations using `up.transition()` and
16229
16607
 
16230
16608
  See [W3C documentation](http://www.w3.org/TR/css3-transitions/#transition-timing-function)
16231
16609
  for a list of pre-defined timing functions.
16232
- @param {boolean} [config.enabled=true]
16610
+ @param {boolean} [config.enabled]
16233
16611
  Whether animation is enabled.
16234
16612
 
16613
+ By default animations are enabled, unless the user has configured their
16614
+ system to [minimize non-essential motion](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion).
16615
+
16235
16616
  Set this to `false` to disable animation globally.
16236
16617
  This can be useful in full-stack integration tests.
16237
16618
  @stable
@@ -16273,15 +16654,19 @@ You can define custom animations using `up.transition()` and
16273
16654
 
16274
16655
  \#\#\# Example
16275
16656
 
16276
- up.animate('.warning', 'fade-in')
16657
+ ```js
16658
+ up.animate('.warning', 'fade-in')
16659
+ ```
16277
16660
 
16278
16661
  You can pass additional options:
16279
16662
 
16280
- up.animate('.warning', 'fade-in', {
16281
- delay: 1000,
16282
- duration: 250,
16283
- easing: 'linear'
16284
- })
16663
+ ```
16664
+ up.animate('.warning', 'fade-in', {
16665
+ delay: 1000,
16666
+ duration: 250,
16667
+ easing: 'linear'
16668
+ })
16669
+ ```
16285
16670
 
16286
16671
  \#\#\# Named animations
16287
16672
 
@@ -16306,9 +16691,11 @@ You can define custom animations using `up.transition()` and
16306
16691
  By passing an object instead of an animation name, you can animate
16307
16692
  the CSS properties of the given element:
16308
16693
 
16309
- var warning = document.querySelector('.warning')
16310
- warning.style.opacity = 0
16311
- up.animate(warning, { opacity: 1 })
16694
+ ```
16695
+ var warning = document.querySelector('.warning')
16696
+ warning.style.opacity = 0
16697
+ up.animate(warning, { opacity: 1 })
16698
+ ```
16312
16699
 
16313
16700
  CSS properties must be given in `kebab-case`, not `camelCase`.
16314
16701
 
@@ -16344,7 +16731,6 @@ You can define custom animations using `up.transition()` and
16344
16731
  var animationFn, runNow, willRun;
16345
16732
  element = up.fragment.get(element);
16346
16733
  options = u.options(options);
16347
- applyConfig(options);
16348
16734
  animationFn = findAnimationFn(animation);
16349
16735
  willRun = willAnimate(element, animation, options);
16350
16736
  if (willRun) {
@@ -16357,6 +16743,7 @@ You can define custom animations using `up.transition()` and
16357
16743
  }
16358
16744
  };
16359
16745
  willAnimate = function(element, animationOrTransition, options) {
16746
+ applyConfig(options);
16360
16747
  return isEnabled() && !isNone(animationOrTransition) && options.duration > 0 && !e.isSingleton(element);
16361
16748
  };
16362
16749
  skipAnimate = function(element, animation) {
@@ -16365,7 +16752,6 @@ You can define custom animations using `up.transition()` and
16365
16752
  }
16366
16753
  return Promise.resolve();
16367
16754
  };
16368
- animCount = 0;
16369
16755
 
16370
16756
  /***
16371
16757
  Animates the given element's CSS properties using CSS transitions.
@@ -16415,7 +16801,7 @@ You can define custom animations using `up.transition()` and
16415
16801
  Animations are completed by jumping to the last animation frame instantly.
16416
16802
  Promises returned by animation and transition functions instantly settle.
16417
16803
 
16418
- Emits the `up:motion:finish` event that is already handled by `up.animate()`.
16804
+ Emits the `up:motion:finish` event that is handled by `up.animate()`.
16419
16805
 
16420
16806
  Does nothing if there are no animation to complete.
16421
16807
 
@@ -16613,18 +16999,20 @@ You can define custom animations using `up.transition()` and
16613
16999
  });
16614
17000
 
16615
17001
  /***
16616
- Defines a named transition that [morphs](/up.element) from one element to another.
17002
+ Defines a named transition that [morphs](/up.morph) from one element to another.
16617
17003
 
16618
17004
  \#\#\# Example
16619
17005
 
16620
17006
  Here is the definition of the pre-defined `cross-fade` animation:
16621
17007
 
16622
- up.transition('cross-fade', (oldElement, newElement, options) ->
16623
- Promise.all([
16624
- up.animate(oldElement, 'fade-out', options),
16625
- up.animate(newElement, 'fade-in', options)
16626
- ])
16627
- )
17008
+ ```js
17009
+ up.transition('cross-fade', (oldElement, newElement, options) ->
17010
+ Promise.all([
17011
+ up.animate(oldElement, 'fade-out', options),
17012
+ up.animate(newElement, 'fade-in', options)
17013
+ ])
17014
+ )
17015
+ ```
16628
17016
 
16629
17017
  It is recommended that your transitions use [`up.animate()`](/up.animate),
16630
17018
  passing along the `options` that were passed to you.
@@ -16659,10 +17047,12 @@ You can define custom animations using `up.transition()` and
16659
17047
 
16660
17048
  Here is the definition of the pre-defined `fade-in` animation:
16661
17049
 
16662
- up.animation('fade-in', function(element, options) {
16663
- element.style.opacity = 0
16664
- up.animate(element, { opacity: 1 }, options)
16665
- })
17050
+ ```js
17051
+ up.animation('fade-in', function(element, options) {
17052
+ element.style.opacity = 0
17053
+ up.animate(element, { opacity: 1 }, options)
17054
+ })
17055
+ ```
16666
17056
 
16667
17057
  It is recommended that your definitions always end by calling
16668
17058
  calling [`up.animate()`](/up.animate) with an object argument, passing along
@@ -16671,7 +17061,7 @@ You can define custom animations using `up.transition()` and
16671
17061
  If you choose to *not* use `up.animate()` and roll your own
16672
17062
  animation code instead, your code must honor the following contract:
16673
17063
 
16674
- 1. It must honor the options `{ duration, easing }` if given
17064
+ 1. It must honor the options `{ duration, easing }`, if given.
16675
17065
  2. It must *not* remove any of the given elements from the DOM.
16676
17066
  3. It returns a promise that is fulfilled when the transition has ended
16677
17067
  4. If during the animation an event `up:motion:finish` is emitted on
@@ -16730,7 +17120,7 @@ You can define custom animations using `up.transition()` and
16730
17120
  e.setStyle(element, translateCSS(0, 0));
16731
17121
  return element.getBoundingClientRect();
16732
17122
  };
16733
- registerMoveMotions = function(direction, boxToTransform) {
17123
+ registerMoveAnimations = function(direction, boxToTransform) {
16734
17124
  var animationFromName, animationToName;
16735
17125
  animationToName = "move-to-" + direction;
16736
17126
  animationFromName = "move-from-" + direction;
@@ -16748,22 +17138,22 @@ You can define custom animations using `up.transition()` and
16748
17138
  return animateNow(element, translateCSS(0, 0), options);
16749
17139
  });
16750
17140
  };
16751
- registerMoveMotions('top', function(box) {
17141
+ registerMoveAnimations('top', function(box) {
16752
17142
  var travelDistance;
16753
17143
  travelDistance = box.top + box.height;
16754
17144
  return translateCSS(0, -travelDistance);
16755
17145
  });
16756
- registerMoveMotions('bottom', function(box) {
17146
+ registerMoveAnimations('bottom', function(box) {
16757
17147
  var travelDistance;
16758
17148
  travelDistance = up.viewport.rootHeight() - box.top;
16759
17149
  return translateCSS(0, travelDistance);
16760
17150
  });
16761
- registerMoveMotions('left', function(box) {
17151
+ registerMoveAnimations('left', function(box) {
16762
17152
  var travelDistance;
16763
17153
  travelDistance = box.left + box.width;
16764
17154
  return translateCSS(-travelDistance, 0);
16765
17155
  });
16766
- registerMoveMotions('right', function(box) {
17156
+ registerMoveAnimations('right', function(box) {
16767
17157
  var travelDistance;
16768
17158
  travelDistance = up.viewport.rootWidth() - box.left;
16769
17159
  return translateCSS(travelDistance, 0);
@@ -16778,10 +17168,17 @@ You can define custom animations using `up.transition()` and
16778
17168
  [Follows](/a-up-follow) this link and swaps in the new fragment
16779
17169
  with an animated transition.
16780
17170
 
17171
+ Note that transitions are not possible when replacing the `body`
17172
+ element.
17173
+
16781
17174
  \#\#\# Example
16782
17175
 
16783
17176
  ```html
16784
- <a href="/page2" up-transition="move-left">Next page</a>
17177
+ <a href="/page2"
17178
+ up-target=".story"
17179
+ up-transition="move-left">
17180
+ Next page
17181
+ </a>
16785
17182
  ```
16786
17183
 
16787
17184
  @selector a[up-transition]
@@ -16793,6 +17190,7 @@ You can define custom animations using `up.transition()` and
16793
17190
  The transition to use when the server responds with an error code.
16794
17191
 
16795
17192
  @see server-errors
17193
+ @stable
16796
17194
  */
16797
17195
 
16798
17196
  /***
@@ -16802,7 +17200,9 @@ You can define custom animations using `up.transition()` and
16802
17200
  \#\#\# Example
16803
17201
 
16804
17202
  ```html
16805
- <form action="/tasks" up-transition="cross-fade">
17203
+ <form action="/tasks"
17204
+ up-target=".content"
17205
+ up-transition="cross-fade">
16806
17206
  ...
16807
17207
  </form>
16808
17208
  ```
@@ -16816,6 +17216,7 @@ You can define custom animations using `up.transition()` and
16816
17216
  The transition to use when the server responds with an error code.
16817
17217
 
16818
17218
  @see server-errors
17219
+ @stable
16819
17220
  */
16820
17221
  up.on('up:framework:boot', warnIfDisabled);
16821
17222
  up.on('up:framework:reset', reset);
@@ -16856,43 +17257,25 @@ You can define custom animations using `up.transition()` and
16856
17257
  Network requests
16857
17258
  ================
16858
17259
 
16859
- TODO: Rewrite this page
16860
-
16861
- Unpoly comes with a number of tricks to shorten the latency between browser and server.
16862
-
16863
- \#\#\# Server responses are cached by default
16864
-
16865
- Unpoly caches server responses for a few minutes,
16866
- making requests to these URLs return instantly.
16867
- All Unpoly functions and selectors go through this cache, unless
16868
- you explicitly pass a `{ cache: false }` option or set an `up-cache="false"` attribute.
16869
-
16870
- The cache holds up to 50 responses for 5 minutes. You can configure the cache size and expiry using
16871
- [`up.network.config`](/up.network.config), or clear the cache manually using [`up.cache.clear()`](/up.cache.clear).
16872
-
16873
- Also the entire cache is cleared with every non-`GET` request (like `POST` or `PUT`).
17260
+ Unpoly ships with an optimized HTTP client for fast and effective
17261
+ communication with your server-side app.
16874
17262
 
16875
- If you need to make cache-aware requests from your [custom JavaScript](/up.syntax),
16876
- use [`up.request()`](/up.request).
17263
+ While you can use the browser's native `fetch()` function,
17264
+ Unpoly's `up.request()` has a number of convenience features:
16877
17265
 
16878
- \#\#\# Preloading links
17266
+ - Requests may be [cached](/up.request#options.cache) to reuse responses and enable [preloading](/a-up-preload).
17267
+ - Requests send [additional HTTP headers](/up.protocol) that the server may use to optimize its response.
17268
+ For example, when updating a [fragment](/up.fragment), the fragment's selector is automatically sent
17269
+ as an `X-Up-Target` header. The server may choose to only render the targeted fragment.
17270
+ - Useful events like `up:request:loaded` or `up:request:late` are emitted throughout the request/response
17271
+ lifecycle.
17272
+ - When too many requests are sent concurrently, excessive requests are [queued](/up.network.config#config.concurrency).
17273
+ This prevents exhausting the user's bandwidth and limits race conditions in end-to-end tests.
17274
+ - A very concise API requiring zero boilerplate code.
16879
17275
 
16880
- Unpoly also lets you speed up reaction times by [preloading
16881
- links](/a-up-preload) when the user hovers over the click area (or puts the mouse/finger
16882
- down). This way the response will already be cached when
16883
- the user releases the mouse/finger.
16884
-
16885
- \#\#\# Spinners
16886
-
16887
- You can listen to the [`up:request:late`](/up:request:late) event to implement a spinner
16888
- that appears during a long-running request.
16889
-
16890
- \#\#\# More acceleration
16891
-
16892
- Other Unpoly modules contain even more tricks to outsmart network latency:
16893
-
16894
- - [Instantaneous feedback for links that are currently loading](/a.up-active)
16895
- - [Follow links on `mousedown` instead of `click`](/a-up-instant)
17276
+ @see up.request
17277
+ @see up.Response
17278
+ @see up:request:late
16896
17279
 
16897
17280
  @module up.network
16898
17281
  */
@@ -16910,8 +17293,8 @@ You can define custom animations using `up.transition()` and
16910
17293
  Additional requests are queued. [Preload](/a-up-preload) requests are
16911
17294
  always queued behind non-preload requests.
16912
17295
 
16913
- You might find it useful to set the request concurrency `1` in full-stack
16914
- integration tests (e.g. Selenium) to prevent race conditions.
17296
+ You might find it useful to set the request concurrency `1` in end-to-end tests
17297
+ to prevent race conditions.
16915
17298
 
16916
17299
  Note that your browser might [impose its own request limit](http://www.browserscope.org/?category=network)
16917
17300
  regardless of what you configure here.
@@ -17013,7 +17396,7 @@ You can define custom animations using `up.transition()` and
17013
17396
 
17014
17397
  @stable
17015
17398
  */
17016
- var abortRequests, cache, config, handleCaching, isBusy, isIdle, isSafeMethod, makeRequest, mimicLocalRequest, parseRequestOptions, preload, queue, queueRequest, registerAliasForRedirect, reset, shouldReduceRequests, useCachedRequest;
17399
+ var abortRequests, cache, config, handleCaching, isBusy, isIdle, isSafeMethod, makeRequest, mimicLocalRequest, parseRequestOptions, queue, queueRequest, registerAliasForRedirect, reset, shouldReduceRequests, useCachedRequest;
17017
17400
  config = new up.Config(function() {
17018
17401
  return {
17019
17402
  concurrency: 4,
@@ -17071,13 +17454,24 @@ You can define custom animations using `up.transition()` and
17071
17454
  /***
17072
17455
  Removes all [cache](/up.cache.get) entries.
17073
17456
 
17074
- Unpoly also automatically clears the cache whenever it processes
17075
- a request with an [unsafe](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1)
17076
- HTTP method like `POST`.
17457
+ To only remove some cache entries, pass a [URL pattern](/url-patterns):
17458
+
17459
+ ```js
17460
+ up.cache.clear('/users/*')
17461
+ ```
17462
+
17463
+ \#\#\# Other reasons the cache may clear
17464
+
17465
+ By default Unpoly automatically clears the entire cache whenever it processes
17466
+ a request with an non-GET HTTP method. To customize this rule, use `up.network.config.clearCache`.
17077
17467
 
17078
17468
  The server may also clear the cache by sending an [`X-Up-Cache: clear`](/X-Up-Cache) header.
17079
17469
 
17080
17470
  @function up.cache.clear
17471
+ @param {string} [pattern]
17472
+ A [URL pattern](/url-patterns) matching cache entries that should be cleared.
17473
+
17474
+ If omitted, the entire cache is cleared.
17081
17475
  @stable
17082
17476
  */
17083
17477
 
@@ -17135,39 +17529,45 @@ You can define custom animations using `up.transition()` and
17135
17529
  Makes an AJAX request to the given URL.
17136
17530
 
17137
17531
  Returns an `up.Request` object which contains information about the request.
17138
- The request object is also a promise for its `up.Response`.
17532
+ This request object is also a promise for an `up.Response` that contains
17533
+ the response text, headers, etc.
17139
17534
 
17140
17535
  \#\#\# Example
17141
17536
 
17142
- let request = up.request('/search', { params: { query: 'sunshine' } })
17143
- console.log('We made a request to', request.url)
17537
+ ```js
17538
+ let request = up.request('/search', { params: { query: 'sunshine' } })
17539
+ console.log('We made a request to', request.url)
17144
17540
 
17145
- let response = await request
17146
- console.log('The response text is', response.text)
17541
+ let response = await request
17542
+ console.log('The response text is', response.text)
17543
+ ```
17147
17544
 
17148
17545
  \#\#\# Error handling
17149
17546
 
17150
17547
  The returned promise will fulfill with an `up.Response` when the server
17151
17548
  responds with an HTTP status of 2xx (like `200`).
17152
17549
 
17153
- When the server responds with an error code (like `422` or `500`), the promise
17550
+ When the server responds with an HTTP error code (like `422` or `500`), the promise
17154
17551
  will *reject* with `up.Response`.
17155
17552
 
17156
17553
  When the request fails from a fatal error (like a timeout or loss of connectivity),
17157
17554
  the promise will reject with an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object.
17158
17555
 
17159
- Here is an example for a complete control flow that also handles errors:
17556
+ Here is an example for a complete control flow that handles both HTTP error codes
17557
+ and fatal errors:
17160
17558
 
17161
- try {
17162
- let response = await up.request('/search', { params: { query: 'sunshine' } })
17163
- console.log('Successful response with text:', response.text)
17164
- } catch (e) {
17165
- if (e instanceof up.Response) {
17166
- console.log('Server responded with HTTP status %s and text %s', e.status, e.text)
17167
- } else {
17168
- console.log('Fatal error during request:', e.message)
17169
- }
17170
- }
17559
+ ```js
17560
+ try {
17561
+ let response = await up.request('/search', { params: { query: 'sunshine' } })
17562
+ console.log('Successful response with text:', response.text)
17563
+ } catch (e) {
17564
+ if (e instanceof up.Response) {
17565
+ console.log('Server responded with HTTP status %s and text %s', e.status, e.text)
17566
+ } else {
17567
+ console.log('Fatal error during request:', e.message)
17568
+ }
17569
+ }
17570
+ ```
17171
17571
 
17172
17572
  \#\#\# Caching
17173
17573
 
@@ -17210,10 +17610,13 @@ You can define custom animations using `up.transition()` and
17210
17610
 
17211
17611
  With `{ cache: false }` (the default) Unpoly will always make a network request.
17212
17612
 
17213
- @param {boolean} [options.clearCache]
17214
- Whether to clear the cache after this request.
17613
+ @param {boolean|string} [options.clearCache]
17614
+ Whether to [clear](/up.cache.clear) the [cache](/up.cache.get) after this request.
17615
+
17616
+ You may also pass a [URL pattern](/url-patterns) to only clear matching requests.
17215
17617
 
17216
- Defaults to the result of `up.network.config.clearCache`.
17618
+ Defaults to the result of `up.network.config.clearCache`, which
17619
+ defaults to clearing the entire cache after a non-GET request.
17217
17620
 
17218
17621
  @param {Object} [options.headers={}]
17219
17622
  An object of additional HTTP headers.
@@ -17238,13 +17641,13 @@ You can define custom animations using `up.transition()` and
17238
17641
  @param {string} [options.target='body']
17239
17642
  The CSS selector that will be sent as an `X-Up-Target` header.
17240
17643
 
17241
- @param {string} [options.layer='current']
17242
- The [layer](/up.layer) this request is associated with.
17243
-
17244
17644
  @param {string} [options.failTarget='body']
17245
17645
  The CSS selector that will be sent as an `X-Up-Fail-Target` header.
17246
17646
 
17247
17647
  @param {string} [options.layer='current']
17648
+ The [layer](/up.layer) this request is associated with.
17649
+
17650
+ @param {string} [options.failLayer='current']
17248
17651
  The [layer](/up.layer) this request is associated with if the server [sends a HTTP status code](/server-errors).
17249
17652
 
17250
17653
  @param {Element} [options.origin]
@@ -17293,18 +17696,8 @@ You can define custom animations using `up.transition()` and
17293
17696
  abortRequests(solo);
17294
17697
  }
17295
17698
  if (clearCache = options.clearCache) {
17296
- return cache.clear(clearCache);
17297
- }
17298
- };
17299
- preload = function() {
17300
- var args, base, options;
17301
- args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
17302
- if (typeof (base = up.migrate).handleNetworkPreloadArgs === "function") {
17303
- base.handleNetworkPreloadArgs.apply(base, args);
17699
+ return cache.clear(clearCache);
17304
17700
  }
17305
- options = parseRequestOptions(args);
17306
- options.preload = true;
17307
- return makeRequest(options);
17308
17701
  };
17309
17702
  parseRequestOptions = function(args) {
17310
17703
  var base, options;
@@ -17417,18 +17810,24 @@ You can define custom animations using `up.transition()` and
17417
17810
 
17418
17811
  Without arguments, this will abort all pending requests:
17419
17812
 
17420
- up.network.abort()
17813
+ ```js
17814
+ up.network.abort()
17815
+ ```
17421
17816
 
17422
17817
  To abort a given `up.Request` object, pass it as the first argument:
17423
17818
 
17424
- let request = up.request('/path')
17425
- up.network.abort(request)
17819
+ ```js
17820
+ let request = up.request('/path')
17821
+ up.network.abort(request)
17822
+ ```
17426
17823
 
17427
17824
  To abort all requests matching a condition, pass a function that takes a request
17428
17825
  and returns a boolean value. Unpoly will abort all request for which the given
17429
17826
  function returns `true`. E.g. to abort all requests with a HTTP method as `GET`:
17430
17827
 
17431
- up.network.abort((request) => request.method == 'GET')
17828
+ ```js
17829
+ up.network.abort((request) => request.method == 'GET')
17830
+ ```
17432
17831
 
17433
17832
  @function up.network.abort
17434
17833
  @param {up.Request|boolean|Function(up.Request): boolean} [matcher=true]
@@ -17590,7 +17989,6 @@ You can define custom animations using `up.transition()` and
17590
17989
  up.on('up:framework:reset', reset);
17591
17990
  return {
17592
17991
  request: makeRequest,
17593
- preload: preload,
17594
17992
  cache: cache,
17595
17993
  isIdle: isIdle,
17596
17994
  isBusy: isBusy,
@@ -17622,15 +18020,30 @@ You can define custom animations using `up.transition()` and
17622
18020
  Layers
17623
18021
  ======
17624
18022
 
17625
- TODO
18023
+ Unpoly allows you to [open page fragments in an overlay](/opening-overlays). Overlays may be stacked infinitely.
18024
+
18025
+ A variety of [overlay modes](/layer-terminology) are supported,
18026
+ such as modal dialogs, popup overlays or drawers. You may [customize their appearance and behavior](/customizing-overlays).
18027
+
18028
+ Layers are isolated, meaning a screen in one layer will not accidentally see elements
18029
+ or events from another layer. For instance, [fragment links](/up.link) will only update elements from the [current layer](/up.layer.current)
18030
+ unless you [explicitly target another layer](/layer-option).
18031
+
18032
+ Overlays allow you to break up a complex screen into [subinteractions](/subinteractions).
18033
+ Subinteractions take place in overlays and may span one or many pages. The original screen remains open in the background.
18034
+ Once the subinteraction is *done*, the overlay is closed and a result value is communicated back to the parent layer.
18035
+
18036
+ @see a[up-layer=new]
18037
+ @see up.layer.current
18038
+ @see up.layer.on
18039
+ @see up.layer.ask
17626
18040
 
17627
18041
  @module up.layer
17628
18042
  */
17629
18043
 
17630
18044
  up.layer = (function() {
17631
- var LAYER_CLASSES, OVERLAY_CLASSES, OVERLAY_MODES, anySelector, api, ask, build, closeCallbackAttr, config, handlers, isOverlayMode, mainTargets, modeConfigs, normalizeOptions, open, openCallbackAttr, optionToString, reset, stack;
18045
+ var LAYER_CLASSES, OVERLAY_CLASSES, anySelector, api, ask, build, closeCallbackAttr, config, handlers, mainTargets, modeConfigs, normalizeOptions, open, openCallbackAttr, optionToString, reset, stack;
17632
18046
  OVERLAY_CLASSES = [up.Layer.Modal, up.Layer.Popup, up.Layer.Drawer, up.Layer.Cover];
17633
- OVERLAY_MODES = u.map(OVERLAY_CLASSES, 'mode');
17634
18047
  LAYER_CLASSES = [up.Layer.Root].concat(OVERLAY_CLASSES);
17635
18048
 
17636
18049
  /***
@@ -17669,7 +18082,7 @@ You can define custom animations using `up.transition()` and
17669
18082
  up.layer.config.modal.openAnimation = 'move-from-top'
17670
18083
  ```
17671
18084
 
17672
- To configure an additional [main target](/main)
18085
+ To configure an additional [main target](/up-main)
17673
18086
  for overlay of any mode:
17674
18087
 
17675
18088
  ```js
@@ -17828,16 +18241,17 @@ You can define custom animations using `up.transition()` and
17828
18241
  });
17829
18242
 
17830
18243
  /***
17831
- TODO: Docs
18244
+ A list of layers that are currently open.
17832
18245
 
17833
- @function up.layer.stack
18246
+ The first element in the list is the [root layer](/up.layer.root).
18247
+ The last element is the [frontmost layer](/up.layer.front).
18248
+
18249
+ @property up.layer.stack
18250
+ @param {List<up.Layer>} stack
17834
18251
  @stable
17835
18252
  */
17836
18253
  stack = null;
17837
18254
  handlers = [];
17838
- isOverlayMode = function(mode) {
17839
- return u.contains(OVERLAY_MODES, mode);
17840
- };
17841
18255
  mainTargets = function(mode) {
17842
18256
  return u.flatMap(modeConfigs(mode), 'mainTargets');
17843
18257
  };
@@ -17961,7 +18375,7 @@ You can define custom animations using `up.transition()` and
17961
18375
  How the overlay may be [dismissed](/closing-overlays) by the user.
17962
18376
 
17963
18377
  Supported values are `'key'`, `'outside'` and `'button'`.
17964
- See [user dismiss controls](/closing-overlays#user-facing-dismiss-controls)
18378
+ See [customizing dismiss controls](/closing-overlays#customizing-dismiss-controls)
17965
18379
  for details.
17966
18380
 
17967
18381
  You may enable multiple dismiss controls by passing an array or
@@ -17975,7 +18389,7 @@ You can define custom animations using `up.transition()` and
17975
18389
  If set to `true` the overlay location and title will be shown in browser UI.
17976
18390
 
17977
18391
  If set to `'auto'` history will be visible if the initial overlay
17978
- content matches a [main target](/main).
18392
+ content matches a [main target](/up-main).
17979
18393
 
17980
18394
  @param {string|Function} [options.animation]
17981
18395
  The opening animation.
@@ -18074,22 +18488,61 @@ You can define custom animations using `up.transition()` and
18074
18488
  };
18075
18489
 
18076
18490
  /***
18077
- TODO: Docs
18078
- TODO: Document that listeners may manipulate options
18079
- TODO: Document that it's emitted on the document
18491
+ This event is emitted before an overlay is opened.
18492
+
18493
+ The overlay is not yet part of the [layer stack](/up.layer.stack) and has not yet been placed
18494
+ in the DOM. Listeners may prevent this event to prevent the overlay from opening.
18495
+
18496
+ The event is emitted on the `document`.
18497
+
18498
+ \#\#\# Changing layer options
18499
+
18500
+ Listeners may inspect and manipulate options for the overlay that is about to open.
18501
+
18502
+ For example, to give overlays the CSS class `.warning` if the initial URL contains
18503
+ the word `"confirm"`:
18504
+
18505
+ ```js
18506
+ up.on('up:layer:open', function(event) {
18507
+ if (event.layerOptions.url.includes('confirm')) {
18508
+ event.layerOptions.class = 'warning'
18509
+ }
18510
+ })
18511
+ ```
18080
18512
 
18081
18513
  @event up:layer:open
18082
18514
  @param {Object} event.layerOptions
18515
+ Options for the overlay that is about to open.
18516
+
18517
+ Listeners may inspect and change the options.
18518
+ All options for `up.layer.open()` may be used.
18083
18519
  @param {Element} event.origin
18520
+ The link element that is opening the overlay.
18521
+ @param event.preventDefault()
18522
+ Event listeners may call this method to prevent the overlay from opening.
18084
18523
  @stable
18085
18524
  */
18086
18525
 
18087
18526
  /***
18088
- TODO: Docs
18527
+ This event is emitted after a new overlay has been placed into the DOM.
18528
+
18529
+ The event is emitted right before the opening animation starts. Because the overlay
18530
+ has not been rendered by the browser, this makes it a good occasion to
18531
+ [customize overlay elements](/customizing-overlays#customizing-overlay-elements):
18532
+
18533
+ ```js
18534
+ up.on('up:layer:opened', function(event) {
18535
+ if (isChristmas()) {
18536
+ up.element.affix(event.layer.element, '.santa-hat', text: 'Merry Christmas!')
18537
+ }
18538
+ })
18539
+ ```
18089
18540
 
18090
18541
  @event up:layer:opened
18091
18542
  @param {Element} event.origin
18543
+ The link element that is opening the overlay.
18092
18544
  @param {up.Layer} event.layer
18545
+ The [layer object](/up.Layer) that is opening.
18093
18546
  @stable
18094
18547
  */
18095
18548
 
@@ -18097,7 +18550,7 @@ You can define custom animations using `up.transition()` and
18097
18550
  This event is emitted after a layer's [location property](/up.Layer.prototype.location)
18098
18551
  has changed value.
18099
18552
 
18100
- This event is also emitted when a layer [without history](/up.Layer.prototype.historyVisible)
18553
+ This event is also emitted when a layer [without visible history](/up.Layer.prototype.historyVisible)
18101
18554
  has reached a new location.
18102
18555
 
18103
18556
  @param {string} event.location
@@ -18133,6 +18586,7 @@ You can define custom animations using `up.transition()` and
18133
18586
  A promise that will settle when the overlay closes.
18134
18587
 
18135
18588
  When the overlay was accepted, the promise will fulfill with the overlay's acceptance value.
18589
+
18136
18590
  When the overlay was dismissed, the promise will reject with the overlay's dismissal value.
18137
18591
 
18138
18592
  @stable
@@ -18164,7 +18618,7 @@ You can define custom animations using `up.transition()` and
18164
18618
  };
18165
18619
 
18166
18620
  /***
18167
- [Follows](/a-up-follow) this link and opens the result in a new layer.
18621
+ [Follows](/a-up-follow) this link and opens the result in a new overlay.
18168
18622
 
18169
18623
  \#\#\# Example
18170
18624
 
@@ -18205,12 +18659,12 @@ You can define custom animations using `up.transition()` and
18205
18659
  If set to `true` the overlay location and title will be shown in browser UI.
18206
18660
 
18207
18661
  If set to `'auto'` history will be visible if the initial overlay
18208
- content matches a [main target](/main).
18662
+ content matches a [main target](/up-main).
18209
18663
 
18210
18664
  @param [up-dismissable]
18211
18665
  How the overlay may be [dismissed](/closing-overlays) by the user.
18212
18666
 
18213
- See [user dismiss controls](/closing-overlays#user-facing-dismiss-controls)
18667
+ See [customizing dismiss controls](/closing-overlays#customizing-dismiss-controls)
18214
18668
  for details.
18215
18669
 
18216
18670
  You may enable multiple dismiss controls by passing a space-separated string.
@@ -18408,12 +18862,33 @@ You can define custom animations using `up.transition()` and
18408
18862
  The *current* layer is usually the [frontmost layer](/up.layer.front).
18409
18863
  There are however some cases where the current layer is a layer in the background:
18410
18864
 
18411
- - While an element in a background layer is [compiled](/up.compiler).
18865
+ - While an element in a background layer is being [compiled](/up.compiler).
18412
18866
  - While an Unpoly event like `up:request:loaded` is being triggered from a background layer.
18413
- - While a running event listener was bound to a background layer using `up.Layer#on()`.
18867
+ - While an event listener bound to a background layer using `up.Layer#on()` is being called.
18414
18868
 
18415
18869
  To temporarily change the current layer from your own code, use `up.Layer#asCurrent()`.
18416
18870
 
18871
+ \#\#\# Remembering the current layer
18872
+
18873
+ Most functions in the `up.layer` package affect the current layer. E.g. `up.layer.dismiss()`
18874
+ is shorthand for `up.layer.current.dismiss()`.
18875
+
18876
+ As described above `up.layer.current` is set to the right layer in compilers and most events,
18877
+ even if that layer is not the frontmost layer.
18878
+
18879
+ If you have async code, the current layer may change when your callback is called.
18880
+ To address this you may retrieve the current layer for later reference:
18881
+
18882
+ ```js
18883
+ function dismissCurrentLayerIn(seconds) {
18884
+ let savedLayer = up.layer.current // returns an up.Layer object
18885
+ let dismiss = () => savedLayer.dismiss()
18886
+ setTimeout(dismiss, seconds * 1000)
18887
+ }
18888
+
18889
+ dismissCurrentLayerIn(10) //
18890
+ ```
18891
+
18417
18892
  @property up.layer.current
18418
18893
  @param {up.Layer} current
18419
18894
  @stable
@@ -18457,6 +18932,9 @@ You can define custom animations using `up.transition()` and
18457
18932
  /***
18458
18933
  Returns the [root layer](/layer-terminology).
18459
18934
 
18935
+ The root layer represents the initial page before any overlay was [opened](/opening-overlays).
18936
+ The root layer always exists and cannot be closed.
18937
+
18460
18938
  @property up.layer.root
18461
18939
  @param {up.Layer} root
18462
18940
  @stable
@@ -18467,7 +18945,10 @@ You can define custom animations using `up.transition()` and
18467
18945
 
18468
18946
  If no overlay is open, an empty array is returned.
18469
18947
 
18470
- @function up.layer.overlays
18948
+ To get an array of *all* layers including the [root layer](/up.layer.root),
18949
+ use `up.layer.stack`.
18950
+
18951
+ @property up.layer.overlays
18471
18952
  @param {Array<up.Layer>} overlays
18472
18953
  @stable
18473
18954
  */
@@ -18492,9 +18973,9 @@ You can define custom animations using `up.transition()` and
18492
18973
  Afterwards the only remaining layer will be the [root layer](/up.layer.root).
18493
18974
 
18494
18975
  @function up.layer.dismissOverlays
18495
- @param {any} value
18976
+ @param {any} [value]
18496
18977
  The dismissal value.
18497
- @param {Object} options
18978
+ @param {Object} [options]
18498
18979
  See options for `up.layer.dismiss()`.
18499
18980
  @stable
18500
18981
  */
@@ -18505,13 +18986,13 @@ You can define custom animations using `up.transition()` and
18505
18986
  /***
18506
18987
  [Accepts](/closing-overlays) the [current layer](up.layer.current).
18507
18988
 
18508
- This is a shortcut for `up.layer.current.dismiss()`.
18509
- See `up.Layer#dismiss()` for more documentation.
18989
+ This is a shortcut for `up.layer.current.accept()`.
18990
+ See `up.Layer#accept()` for more documentation.
18510
18991
 
18511
- @function up.layer.dismiss
18992
+ @function up.layer.accept
18512
18993
  @param {any} [value]
18513
18994
  @param {Object} [options]
18514
- @return
18995
+ @stable
18515
18996
  */
18516
18997
 
18517
18998
  /***
@@ -18523,7 +19004,7 @@ You can define custom animations using `up.transition()` and
18523
19004
  @function up.layer.dismiss
18524
19005
  @param {any} [value]
18525
19006
  @param {Object} [options]
18526
- @return
19007
+ @stable
18527
19008
  */
18528
19009
 
18529
19010
  /***
@@ -18532,7 +19013,7 @@ You can define custom animations using `up.transition()` and
18532
19013
  This is a shortcut for `up.layer.current.isRoot()`.
18533
19014
  See `up.Layer#isRoot()` for more documentation..
18534
19015
 
18535
- @function up.layer.isFront
19016
+ @function up.layer.isRoot
18536
19017
  @return {boolean}
18537
19018
  @stable
18538
19019
  */
@@ -18560,7 +19041,7 @@ You can define custom animations using `up.transition()` and
18560
19041
  */
18561
19042
 
18562
19043
  /***
18563
- Listens to a ([DOM event](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events)
19044
+ Listens to a [DOM event](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events)
18564
19045
  that originated on an element [contained](/up.Layer.prototype.contains) by the [current layer](/up.layer.current).
18565
19046
 
18566
19047
  This is a shortcut for `up.layer.current.on()`.
@@ -18569,7 +19050,7 @@ You can define custom animations using `up.transition()` and
18569
19050
  @function up.layer.on
18570
19051
  @param {string} types
18571
19052
  A space-separated list of event types to bind to.
18572
- @param {string} [selector]
19053
+ @param {string|Function(): string} [selector]
18573
19054
  The selector of an element on which the event must be triggered.
18574
19055
  @param {Object} [options]
18575
19056
  @param {Function(event, [element], [data])} listener
@@ -18586,9 +19067,8 @@ You can define custom animations using `up.transition()` and
18586
19067
  See `up.Layer#off()` for more documentation.
18587
19068
 
18588
19069
  @function up.layer.off
18589
- @param {Element|jQuery} [element=document]
18590
19070
  @param {string} events
18591
- @param {string} [selector]
19071
+ @param {string|Function(): string} [selector]
18592
19072
  @param {Function(event, [element], [data])} listener
18593
19073
  The listener function to unbind.
18594
19074
  @stable
@@ -18601,7 +19081,6 @@ You can define custom animations using `up.transition()` and
18601
19081
  See `up.Layer#emit()` for more documentation.
18602
19082
 
18603
19083
  @function up.layer.emit
18604
- @param {Element|jQuery} [target=up.layer.element]
18605
19084
  @param {string} eventType
18606
19085
  @param {Object} [props={}]
18607
19086
  @stable
@@ -18631,7 +19110,7 @@ You can define custom animations using `up.transition()` and
18631
19110
  */
18632
19111
 
18633
19112
  /***
18634
- The location of the [current layer](/up.layer.current).
19113
+ The location URL of the [current layer](/up.layer.current).
18635
19114
 
18636
19115
  This is a shortcut for `up.layer.current.location`.
18637
19116
  See `up.Layer#location` for more documentation.
@@ -18640,23 +19119,34 @@ You can define custom animations using `up.transition()` and
18640
19119
  @param {string} location
18641
19120
  @stable
18642
19121
  */
19122
+
19123
+ /***
19124
+ The [current layer](/up.layer.current)'s [mode](/up.layer.mode)
19125
+ which governs its appearance and behavior.
19126
+
19127
+ @property up.layer.mode
19128
+ @param {string} mode
19129
+ @stable
19130
+ */
19131
+
19132
+ /***
19133
+ The [context](/context) of the [current layer](/up.layer.current).
19134
+
19135
+ This is aliased as `up.context`.
19136
+
19137
+ @property up.layer.context
19138
+ @param {string} context
19139
+ The context object.
19140
+
19141
+ If no context has been set an empty object is returned.
19142
+ @experimental
19143
+ */
18643
19144
  u.delegate(api, ['accept', 'dismiss', 'isRoot', 'isOverlay', 'isFront', 'on', 'off', 'emit', 'parent', 'historyVisible', 'location', 'mode', 'context', 'element', 'contains', 'size', 'affix'], function() {
18644
19145
  return stack.current;
18645
19146
  });
18646
19147
  return api;
18647
19148
  })();
18648
19149
 
18649
-
18650
- /***
18651
- TODO: Docs
18652
- @property up.context
18653
- @pram {Object} context
18654
- */
18655
-
18656
- u.getter(up, 'context', function() {
18657
- return up.layer.context;
18658
- });
18659
-
18660
19150
  }).call(this);
18661
19151
 
18662
19152
  /***
@@ -18729,6 +19219,11 @@ With these [`up-target`](/a-up-follow#up-target) annotations Unpoly only updates
18729
19219
  The JavaScript environment will persist and the user will not see a white flash while the
18730
19220
  new page is loading.
18731
19221
 
19222
+ @see a[up-follow]
19223
+ @see a[up-instant]
19224
+ @see a[up-preload]
19225
+ @see up.follow
19226
+
18732
19227
  @module up.link
18733
19228
  */
18734
19229
 
@@ -18736,7 +19231,7 @@ new page is loading.
18736
19231
  var slice = [].slice;
18737
19232
 
18738
19233
  up.link = (function() {
18739
- 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;
19234
+ 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;
18740
19235
  u = up.util;
18741
19236
  e = up.element;
18742
19237
  linkPreloader = new up.LinkPreloader();
@@ -18753,9 +19248,10 @@ new page is loading.
18753
19248
  };
18754
19249
 
18755
19250
  /***
18756
- TODO: Docs
18757
- TODO: Doucment that noInstantSelectors and noPreloadSelectors inherit from noFollowSelectors
18758
- TODO: Document that noFollowSelectors already excludes cross-origin, rel=download, [target], [href^=#], javascript: hrefs
19251
+ Configures defaults for link handling.
19252
+
19253
+ In particular you can configure Unpoly to handle [all links on the page](/handling-everything)
19254
+ without requiring developers to set `[up-...]` attributes.
18759
19255
 
18760
19256
  @property up.link.config
18761
19257
 
@@ -18828,7 +19324,7 @@ new page is loading.
18828
19324
 
18829
19325
  If set to `false`, Unpoly will never preload links.
18830
19326
 
18831
- @param {Array<string>} [config.cickableSelectors]
19327
+ @param {Array<string>} [config.clickableSelectors]
18832
19328
  A list of CSS selectors matching elements that should behave like links or buttons.
18833
19329
 
18834
19330
  @see [up-clickable]
@@ -18837,7 +19333,7 @@ new page is loading.
18837
19333
  config = new up.Config(function() {
18838
19334
  return {
18839
19335
  followSelectors: combineFollowableSelectors(LINKS_WITH_REMOTE_HTML, ATTRIBUTES_SUGGESTING_FOLLOW).concat(LINKS_WITH_LOCAL_HTML),
18840
- noFollowSelectors: ['[up-follow=false]', 'a[rel=download]', 'a[target]', 'a[href^="#"]:not([up-content]):not([up-fragment]):not([up-document])', 'a[href^="javascript:"]'],
19336
+ noFollowSelectors: ['[up-follow=false]', 'a[download]', 'a[target]', 'a[href^="#"]:not([up-content]):not([up-fragment]):not([up-document])', 'a[href^="javascript:"]'],
18841
19337
  instantSelectors: ['[up-instant]'],
18842
19338
  noInstantSelectors: ['[up-instant=false]', '[onclick]'],
18843
19339
  preloadSelectors: combineFollowableSelectors(LINKS_WITH_REMOTE_HTML, ['[up-preload]']),
@@ -18900,10 +19396,9 @@ new page is loading.
18900
19396
  };
18901
19397
 
18902
19398
  /***
18903
- Fetches the given link's `[href]` with JavaScript and [replaces](/up.replace) the
18904
- [current layer](/up.layer.current) with HTML from the response.
19399
+ Follows the given link with JavaScript and updates a fragment with the server response.
18905
19400
 
18906
- By default the layer's [main element](/main)
19401
+ By default the layer's [main element](/up-main)
18907
19402
  will be replaced. Attributes like `a[up-target]`
18908
19403
  or `a[up-layer]` will be honored.
18909
19404
 
@@ -18965,8 +19460,24 @@ new page is loading.
18965
19460
  };
18966
19461
 
18967
19462
  /***
18968
- Parses the `render()` options that would be used to
18969
- [`follow`](/up.follow) the given link, but does not [render](/up.render).
19463
+ Parses the [render](/up.render) options that would be used to
19464
+ [`follow`](/up.follow) the given link, but does not render.
19465
+
19466
+ \#\#\# Example
19467
+
19468
+ Given a link with some `[up-...]` attributes:
19469
+
19470
+ ```html
19471
+ <a href="/foo" up-target=".content" up-layer="new">...</a>
19472
+ ```
19473
+
19474
+ We can parse the link's render options like this:
19475
+
19476
+ ```js
19477
+ let link = document.querySelector('a[href="/foo"]')
19478
+ let options = up.link.followOptions(link)
19479
+ // => { url: '/foo', method: 'GET', target: '.content', layer: 'new', ... }
19480
+ ```
18970
19481
 
18971
19482
  @function up.link.followOptions
18972
19483
  @param {Element|jQuery|string} link
@@ -19045,7 +19556,20 @@ new page is loading.
19045
19556
 
19046
19557
  The event is emitted on the `<a>` element that is being followed.
19047
19558
 
19048
- TODO: Document that listeners may manipulate options
19559
+ \#\#\# Changing render options
19560
+
19561
+ Listeners may inspect and manipulate [render options](/up.render) for the coming fragment update.
19562
+
19563
+ The code below will open all form-contained links in an overlay, as to not
19564
+ lose the user's form data:
19565
+
19566
+ ```js
19567
+ up.on('up:link:follow', function(event, link) {
19568
+ if (link.closest('form')) {
19569
+ event.renderOptions.layer = 'new'
19570
+ }
19571
+ })
19572
+ ```
19049
19573
 
19050
19574
  @event up:link:follow
19051
19575
  @param {Element} event.target
@@ -19071,7 +19595,10 @@ new page is loading.
19071
19595
  @param {Object} options
19072
19596
  See options for `up.follow()`.
19073
19597
  @return {Promise}
19074
- A promise that will be fulfilled when the request was loaded and cached
19598
+ A promise that will be fulfilled when the request was loaded and cached.
19599
+
19600
+ When preloading is [disabled](/up.link.config#config.preloadEnabled) the promise
19601
+ rejects with an `AbortError`.
19075
19602
  @stable
19076
19603
  */
19077
19604
  preload = function(link, options) {
@@ -19175,7 +19702,7 @@ new page is loading.
19175
19702
  @function up.link.makeFollowable
19176
19703
  @param {Element|jQuery|string} link
19177
19704
  The element or selector for the link to make followable.
19178
- @stable
19705
+ @experimental
19179
19706
  */
19180
19707
  makeFollowable = function(link) {
19181
19708
  if (!isFollowable(link)) {
@@ -19311,6 +19838,13 @@ new page is loading.
19311
19838
  If the user activates an element using their keyboard, the `up:click` event will be emitted
19312
19839
  when the key is pressed even if the element has an `[up-instant]` attribute.
19313
19840
 
19841
+ \#\#\# Only unmodified clicks are considered
19842
+
19843
+ To prevent overriding native browser behavior, the `up:click` is only emitted for unmodified clicks.
19844
+
19845
+ In particular, it is not emitted when the user holds `Shift`, `CTRL` or `Meta` while clicking.
19846
+ Neither it is emitted when the user clicks with a secondary mouse button.
19847
+
19314
19848
  @event up:click
19315
19849
  @param {Element} event.target
19316
19850
  The clicked element.
@@ -19333,24 +19867,9 @@ new page is loading.
19333
19867
  method = followMethod(link);
19334
19868
  return up.network.isSafeMethod(method);
19335
19869
  };
19336
- targetMacro = function(queryAttr, fixedResultAttrs, callback) {
19337
- return up.macro("[" + queryAttr + "]", function(link) {
19338
- var optionalTarget, resultAttrs;
19339
- resultAttrs = u.copy(fixedResultAttrs);
19340
- if (optionalTarget = link.getAttribute(queryAttr)) {
19341
- resultAttrs['up-target'] = optionalTarget;
19342
- } else {
19343
- resultAttrs['up-follow'] = '';
19344
- }
19345
- e.setMissingAttrs(link, resultAttrs);
19346
- link.removeAttribute(queryAttr);
19347
- return typeof callback === "function" ? callback() : void 0;
19348
- });
19349
- };
19350
19870
 
19351
19871
  /***
19352
- [Follows](/up.follow) this link with JavaScript and replaces a CSS selector
19353
- on the current page with a corresponding element from the response.
19872
+ [Follows](/up.follow) this link with JavaScript and updates a fragment with the server response.
19354
19873
 
19355
19874
  Following a link is considered [navigation](/navigation) by default.
19356
19875
 
@@ -19363,7 +19882,7 @@ new page is loading.
19363
19882
  <a href="/posts/5" up-follow up-target=".content">Read post</a>
19364
19883
  ```
19365
19884
 
19366
- If no `[up-target]` attribute is set, the [main target](/main) is updated.
19885
+ If no `[up-target]` attribute is set, the [main target](/up-main) is updated.
19367
19886
 
19368
19887
  \#\#\# Advanced fragment changes
19369
19888
 
@@ -19379,7 +19898,7 @@ new page is loading.
19379
19898
  - `[up-transition]`
19380
19899
  - `[up-content]`
19381
19900
  - `[up-fragment]`
19382
- - `[up-document]'
19901
+ - `[up-document]`
19383
19902
 
19384
19903
  Such a link will still be followed through Unpoly.
19385
19904
 
@@ -19400,14 +19919,14 @@ new page is loading.
19400
19919
  @param [up-target]
19401
19920
  The CSS selector to update.
19402
19921
 
19403
- If omitted a [main target](/main) will be rendered.
19922
+ If omitted a [main target](/up-main) will be rendered.
19404
19923
 
19405
19924
  @param [up-fallback]
19406
19925
  Specifies behavior if the [target selector](/up.render#options.target) is missing from the current page or the server response.
19407
19926
 
19408
19927
  If set to a CSS selector, Unpoly will attempt to replace that selector instead.
19409
19928
 
19410
- If set to `true` Unpoly will attempt to replace a [main target](/main) instead.
19929
+ If set to `true` Unpoly will attempt to replace a [main target](/up-main) instead.
19411
19930
 
19412
19931
  If set to `false` Unpoly will immediately reject the render promise.
19413
19932
 
@@ -19481,12 +20000,12 @@ new page is loading.
19481
20000
 
19482
20001
  If set to `auto` history will be updated if the `[up-target]` matches
19483
20002
  a selector in `up.fragment.config.autoHistoryTargets`. By default this contains all
19484
- [main targets](/main).
20003
+ [main targets](/up-main).
19485
20004
 
19486
20005
  If set to `false`, the history will remain unchanged.
19487
20006
 
19488
20007
  [Overlays](/up.layer) will only change the browser URL and window title if the overlay
19489
- has [visible history](/up.layer.historyVisible), even with `{ history: true }`.
20008
+ has [visible history](/up.layer.historyVisible), even when `[up-history=true]` is set.
19490
20009
 
19491
20010
  @param [up-title]
19492
20011
  An explicit document title to use after rendering.
@@ -19561,7 +20080,7 @@ new page is loading.
19561
20080
  This is only relevant when updating a layer that is not the [frontmost layer](/up.layer.front).
19562
20081
 
19563
20082
  @param [up-context]
19564
- A JSON object that will be merged into the [context](/up.context)
20083
+ A JSON object that will be merged into the [context](/context)
19565
20084
  of the current layer once the fragment is rendered.
19566
20085
 
19567
20086
  @param [up-keep='true']
@@ -19616,12 +20135,7 @@ new page is loading.
19616
20135
  });
19617
20136
 
19618
20137
  /***
19619
- TODO: Explain that this generates an up:click event, works on any elements, can can be used to accelerate links
19620
-
19621
- By adding an `up-instant` attribute to a link, the destination will be
19622
- fetched on `mousedown` instead of `click` (`mouseup`).
19623
-
19624
- <a href="/users" up-follow up-instant>User list</a>
20138
+ Follows this link on `mousedown` instead of `click`.
19625
20139
 
19626
20140
  This will save precious milliseconds that otherwise spent
19627
20141
  on waiting for the user to release the mouse button. Since an
@@ -19633,6 +20147,10 @@ new page is loading.
19633
20147
  navigation actions this isn't needed. E.g. popular operation
19634
20148
  systems switch tabs on `mousedown` instead of `click`.
19635
20149
 
20150
+ \#\#\# Example
20151
+
20152
+ <a href="/users" up-follow up-instant>User list</a>
20153
+
19636
20154
  \#\#\# Accessibility
19637
20155
 
19638
20156
  If the user activates an element using their keyboard, the `up:click` event will be emitted
@@ -19642,37 +20160,6 @@ new page is loading.
19642
20160
  @stable
19643
20161
  */
19644
20162
 
19645
- /***
19646
- [Follows](/up.follow) this link as fast as possible.
19647
-
19648
- This is done by:
19649
-
19650
- - [Following the link through AJAX](/a-up-follow) instead of a full page load
19651
- - [Preloading the link's destination URL](/a-up-preload)
19652
- - [Triggering the link on `mousedown`](/a-up-instant) instead of on `click`
19653
-
19654
- \#\#\# Example
19655
-
19656
- Use `[up-dash]` like this:
19657
-
19658
- <a href="/users" up-dash=".main">User list</a>
19659
-
19660
- This is shorthand for:
19661
-
19662
- <a href="/users" up-target=".main" up-instant up-preload>User list</a>
19663
-
19664
- @selector a[up-dash]
19665
- @param [up-dash='body']
19666
- The CSS selector to replace
19667
-
19668
- 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)).
19669
- @stable
19670
- */
19671
- targetMacro('up-dash', {
19672
- 'up-preload': '',
19673
- 'up-instant': ''
19674
- });
19675
-
19676
20163
  /***
19677
20164
  Add an `[up-expand]` attribute to any element to enlarge the click area of a
19678
20165
  descendant link.
@@ -19731,11 +20218,9 @@ new page is loading.
19731
20218
  });
19732
20219
 
19733
20220
  /***
19734
- Links with an `up-preload` attribute will silently fetch their target
19735
- when the user hovers over the click area, or when the user puts her
19736
- mouse/finger down (before releasing).
20221
+ Preloads this link when the user hovers over it.
19737
20222
 
19738
- When the link is clicked later, the response will already be cached,
20223
+ When the link is clicked later the response will already be cached,
19739
20224
  making the interaction feel instant.
19740
20225
 
19741
20226
  @selector a[up-preload]
@@ -19763,7 +20248,6 @@ new page is loading.
19763
20248
  isFollowable: isFollowable,
19764
20249
  shouldFollowEvent: shouldFollowEvent,
19765
20250
  followMethod: followMethod,
19766
- targetMacro: targetMacro,
19767
20251
  convertClicks: convertClicks,
19768
20252
  config: config,
19769
20253
  combineFollowableSelectors: combineFollowableSelectors
@@ -19778,9 +20262,12 @@ new page is loading.
19778
20262
  Forms
19779
20263
  =====
19780
20264
 
19781
- Unpoly comes with functionality to [submit](/form-up-submit) and [validate](/input-up-validate)
19782
- forms without leaving the current page. This means you can replace page fragments,
19783
- open dialogs with sub-forms, etc. all without losing form state.
20265
+ The `up.form` module helps you work with non-trivial forms.
20266
+
20267
+ @see form[up-submit]
20268
+ @see form[up-validate]
20269
+ @see input[up-switch]
20270
+ @see form[up-autosubmit]
19784
20271
 
19785
20272
  @module up.form
19786
20273
  */
@@ -19789,7 +20276,7 @@ open dialogs with sub-forms, etc. all without losing form state.
19789
20276
  var slice = [].slice;
19790
20277
 
19791
20278
  up.form = (function() {
19792
- 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;
20279
+ 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;
19793
20280
  u = up.util;
19794
20281
  e = up.element;
19795
20282
  ATTRIBUTES_SUGGESTING_SUBMIT = ['[up-submit]', '[up-target]', '[up-layer]', '[up-transition]'];
@@ -19966,8 +20453,26 @@ open dialogs with sub-forms, etc. all without losing form state.
19966
20453
  });
19967
20454
 
19968
20455
  /***
19969
- Parses the `render()` options that would be used to
19970
- [`submit`](/up.submit) the given form, but does not [render](/up.render).
20456
+ Parses the [render](/up.render) options that would be used to
20457
+ [`submit`](/up.submit) the given form, but does not render.
20458
+
20459
+ \#\#\# Example
20460
+
20461
+ Given a form element:
20462
+
20463
+ ```html
20464
+ <form action="/foo" method="post" up-target=".content">
20465
+ ...
20466
+ </form>
20467
+ ```
20468
+
20469
+ We can parse the link's render options like this:
20470
+
20471
+ ```js
20472
+ let form = document.querySelector('form')
20473
+ let options = up.form.submitOptions(form)
20474
+ // => { url: '/foo', method: 'POST', target: '.content', ... }
20475
+ ```
19971
20476
 
19972
20477
  @param {Element|jQuery|string} form
19973
20478
  The form to submit.
@@ -20020,14 +20525,29 @@ open dialogs with sub-forms, etc. all without losing form state.
20020
20525
  /***
20021
20526
  This event is [emitted](/up.emit) when a form is [submitted](/up.submit) through Unpoly.
20022
20527
 
20023
- The event is emitted on the`<form>` element.
20528
+ The event is emitted on the `<form>` element.
20529
+
20530
+ When the form is being [validated](/input-up-validate), this event is not emitted.
20531
+ Instead an `up:form:validate` event is emitted.
20532
+
20533
+ \#\#\# Changing render options
20534
+
20535
+ Listeners may inspect and manipulate [render options](/up.render) for the coming fragment update.
20536
+
20537
+ The code below will use a custom [transition](/up-transition)
20538
+ when a form submission [fails](/server-errors):
20539
+
20540
+ ```js
20541
+ up.on('up:form:submit', function(event, form) {
20542
+ event.renderOptions.failTransition = 'shake'
20543
+ })
20544
+ ```
20024
20545
 
20025
20546
  @event up:form:submit
20026
20547
  @param {Element} event.target
20027
20548
  The `<form>` element that will be submitted.
20028
20549
  @param {Object} event.renderOptions
20029
20550
  An object with [render options](/up.render) for the fragment update
20030
- that will show the validation results.
20031
20551
 
20032
20552
  Listeners may inspect and modify these options.
20033
20553
  @param event.preventDefault()
@@ -20035,7 +20555,11 @@ open dialogs with sub-forms, etc. all without losing form state.
20035
20555
  @stable
20036
20556
  */
20037
20557
  up.on('up:click', submitButtonSelector, function(event, button) {
20038
- return button.focus();
20558
+ var form;
20559
+ form = e.closest(button, 'form');
20560
+ if (form && isSubmittable(form)) {
20561
+ return button.focus();
20562
+ }
20039
20563
  });
20040
20564
 
20041
20565
  /***
@@ -20120,10 +20644,10 @@ open dialogs with sub-forms, etc. all without losing form state.
20120
20644
  /***
20121
20645
  [Observes](/up.observe) a field or form and submits the form when a value changes.
20122
20646
 
20123
- Both the form and the changed field will be assigned a CSS class [`form-up-active`](/form-up-active)
20647
+ Both the form and the changed field will be assigned a CSS class [`.up-active`](/form-up-active)
20124
20648
  while the autosubmitted form is processing.
20125
20649
 
20126
- The unobtrusive variant of this is the [`up-autosubmit`](/form-up-autosubmit) attribute.
20650
+ The unobtrusive variant of this is the [`[up-autosubmit]`](/form-up-autosubmit) attribute.
20127
20651
 
20128
20652
  @function up.autosubmit
20129
20653
  @param {string|Element|jQuery} target
@@ -20177,7 +20701,9 @@ open dialogs with sub-forms, etc. all without losing form state.
20177
20701
 
20178
20702
  \#\#\# Example
20179
20703
 
20180
- up.validate('input[name=email]', { target: '.email-errors' })
20704
+ ```js
20705
+ up.validate('input[name=email]', { target: '.email-errors' })
20706
+ ```
20181
20707
 
20182
20708
  @function up.validate
20183
20709
  @param {string|Element|jQuery} field
@@ -20221,6 +20747,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20221
20747
  @param event.preventDefault()
20222
20748
  Event listeners may call this method to prevent the validation request
20223
20749
  being sent to the server.
20750
+ @stable
20224
20751
  */
20225
20752
  switcherValues = function(field) {
20226
20753
  var checkedButton, form, groupName, meta, value, values;
@@ -20333,24 +20860,51 @@ open dialogs with sub-forms, etc. all without losing form state.
20333
20860
  return element;
20334
20861
  }
20335
20862
  };
20863
+
20864
+ /***
20865
+ Returns whether the given form will be [submitted](/up.follow) through Unpoly
20866
+ instead of making a full page load.
20867
+
20868
+ By default Unpoly will follow forms if the element has
20869
+ one of the following attributes:
20870
+
20871
+ - `[up-submit]`
20872
+ - `[up-target]`
20873
+ - `[up-layer]`
20874
+ - `[up-transition]`
20875
+
20876
+ To consider other selectors to be submittable, see `up.form.config.submitSelectors`.
20877
+
20878
+ @function up.form.isSubmittable
20879
+ @param {Element|jQuery|string} form
20880
+ The form to check.
20881
+ @stable
20882
+ */
20883
+ isSubmittable = function(form) {
20884
+ form = up.fragment.get(form);
20885
+ return e.matches(form, fullSubmitSelector()) && !isSubmitDisabled(form);
20886
+ };
20336
20887
  isSubmitDisabled = function(form) {
20337
20888
  return e.matches(form, config.noSubmitSelectors.join(','));
20338
20889
  };
20339
20890
 
20340
20891
  /***
20341
- Forms with an `up-target` attribute are [submitted via AJAX](/up.submit)
20342
- instead of triggering a full page reload.
20343
-
20344
- <form method="post" action="/users" up-target=".main">
20345
- ...
20346
- </form>
20892
+ Submits this form via JavaScript and updates a fragment with the server response.
20347
20893
 
20348
20894
  The server response is searched for the selector given in `up-target`.
20349
20895
  The selector content is then [replaced](/up.replace) in the current page.
20350
20896
 
20351
20897
  The programmatic variant of this is the [`up.submit()`](/up.submit) function.
20352
20898
 
20353
- \#\#\# Failed submission
20899
+ \#\#\# Example
20900
+
20901
+ ```html
20902
+ <form method="post" action="/users" up-submit>
20903
+ ...
20904
+ </form>
20905
+ ```
20906
+
20907
+ \#\#\# Handling validation errors
20354
20908
 
20355
20909
  When the server was unable to save the form due to invalid params,
20356
20910
  it will usually re-render an updated copy of the form with
@@ -20365,19 +20919,35 @@ open dialogs with sub-forms, etc. all without losing form state.
20365
20919
  [`:status` option to `render`](http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option)
20366
20920
  for this:
20367
20921
 
20368
- class UsersController < ApplicationController
20369
-
20370
- def create
20371
- user_params = params[:user].permit(:email, :password)
20372
- @user = User.new(user_params)
20373
- if @user.save?
20374
- sign_in @user
20375
- else
20376
- render 'form', status: :bad_request
20377
- end
20378
- end
20922
+ ```ruby
20923
+ class UsersController < ApplicationController
20379
20924
 
20925
+ def create
20926
+ user_params = params[:user].permit(:email, :password)
20927
+ @user = User.new(user_params)
20928
+ if @user.save?
20929
+ sign_in @user
20930
+ else
20931
+ render 'form', status: :bad_request
20380
20932
  end
20933
+ end
20934
+
20935
+ end
20936
+ ```
20937
+
20938
+ You may define different option for the failure case by infixing an attribute with `fail`:
20939
+
20940
+ ```html
20941
+ <form method="post" action="/action"
20942
+ up-target=".content"
20943
+ up-fail-target="form"
20944
+ up-scroll="auto"
20945
+ up-fail-scroll=".errors">
20946
+ ...
20947
+ </form>
20948
+ ```
20949
+
20950
+ See [handling server errors](/server-errors) for details.
20381
20951
 
20382
20952
  Note that you can also use
20383
20953
  [`input[up-validate]`](/input-up-validate) to perform server-side
@@ -20385,7 +20955,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20385
20955
 
20386
20956
  \#\#\# Giving feedback while the form is processing
20387
20957
 
20388
- The `<form>` element will be assigned a CSS class [`up-active`](/form.up-active) while
20958
+ The `<form>` element will be assigned a CSS class [`.up-active`](/form.up-active) while
20389
20959
  the submission is loading.
20390
20960
 
20391
20961
  \#\#\# Short notation
@@ -20569,11 +21139,13 @@ open dialogs with sub-forms, etc. all without losing form state.
20569
21139
  */
20570
21140
 
20571
21141
  /***
20572
- Performs [server-side validation](/input-up-validate) when any fieldset within this form changes.
21142
+ Validates this form on the server when any field changes and shows validation errors.
20573
21143
 
20574
21144
  You can configure what Unpoly considers a fieldset by adding CSS selectors to the
20575
21145
  `up.form.config.validateTargets` array.
20576
21146
 
21147
+ See `input[up-validate]` for detailed documentation.
21148
+
20577
21149
  @selector form[up-validate]
20578
21150
  @param up-validate
20579
21151
  The CSS selector to update with the server response.
@@ -20590,7 +21162,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20590
21162
  });
20591
21163
 
20592
21164
  /***
20593
- Show or hide elements when a `<select>` or `<input>` has a given value.
21165
+ Show or hide elements when a form field is set to a given value.
20594
21166
 
20595
21167
  \#\#\# Example: Select options
20596
21168
 
@@ -20710,6 +21282,15 @@ open dialogs with sub-forms, etc. all without losing form state.
20710
21282
 
20711
21283
  <input name="query" up-observe="showSuggestions(value)">
20712
21284
 
21285
+ Note that the parameter name in the markup must be called `value` or it will not work.
21286
+ The parameter name can be called whatever you want in the JavaScript, however.
21287
+
21288
+ Also note that the function must be declared on the `window` object to work, like so:
21289
+
21290
+ window.showSuggestions = function(selectedValue) {
21291
+ console.log(`Called showSuggestions() with ${selectedValue}`);
21292
+ }
21293
+
20713
21294
  \#\#\# Callback context
20714
21295
 
20715
21296
  The script given to `[up-observe]` runs with the following context:
@@ -20784,7 +21365,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20784
21365
  /***
20785
21366
  Submits this field's form when this field changes its values.
20786
21367
 
20787
- Both the form and the changed field will be assigned a CSS class [`up-active`](/form-up-active)
21368
+ Both the form and the changed field will be assigned a CSS class [`.up-active`](/form-up-active)
20788
21369
  while the autosubmitted form is loading.
20789
21370
 
20790
21371
  The programmatic variant of this is the [`up.autosubmit()`](/up.autosubmit) function.
@@ -20813,15 +21394,15 @@ open dialogs with sub-forms, etc. all without losing form state.
20813
21394
  </div>
20814
21395
 
20815
21396
  @selector input[up-autosubmit]
20816
- @param up-delay
21397
+ @param [up-delay]
20817
21398
  The number of miliseconds to wait after a change before the form is submitted.
20818
21399
  @stable
20819
21400
  */
20820
21401
 
20821
21402
  /***
20822
- Submits the form when *any* field changes.
21403
+ Submits the form when any field changes.
20823
21404
 
20824
- Both the form and the field will be assigned a CSS class [`up-active`](/form-up-active)
21405
+ Both the form and the field will be assigned a CSS class [`.up-active`](/form-up-active)
20825
21406
  while the autosubmitted form is loading.
20826
21407
 
20827
21408
  The programmatic variant of this is the [`up.autosubmit()`](/up.autosubmit) function.
@@ -20836,7 +21417,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20836
21417
  </form>
20837
21418
 
20838
21419
  @selector form[up-autosubmit]
20839
- @param up-delay
21420
+ @param [up-delay]
20840
21421
  The number of miliseconds to wait after a change before the form is submitted.
20841
21422
  @stable
20842
21423
  */
@@ -20848,6 +21429,7 @@ open dialogs with sub-forms, etc. all without losing form state.
20848
21429
  config: config,
20849
21430
  submit: submit,
20850
21431
  submitOptions: submitOptions,
21432
+ isSubmittable: isSubmittable,
20851
21433
  observe: observe,
20852
21434
  validate: validate,
20853
21435
  autosubmit: autosubmit,
@@ -20873,44 +21455,57 @@ Navigation feedback
20873
21455
  ===================
20874
21456
 
20875
21457
  The `up.feedback` module adds useful CSS classes to links while they are loading,
20876
- or when they point to the current URL. By styling these classes you may
20877
- provide instant feedback to user interactions. This improves the perceived speed of your interface.
21458
+ or when they point to the current URL.
21459
+
21460
+ By styling these classes you may provide instant feedback to user interactions,
21461
+ improving the perceived speed of your interface.
20878
21462
 
20879
21463
 
20880
21464
  \#\#\# Example
20881
21465
 
20882
21466
  Let's say we have an `<nav>` element with two links, pointing to `/foo` and `/bar` respectively:
20883
21467
 
20884
- <nav>
20885
- <a href="/foo" up-follow>Foo</a>
20886
- <a href="/bar" up-follow>Bar</a>
20887
- </nav>
21468
+ ```html
21469
+ <nav>
21470
+ <a href="/foo" up-follow>Foo</a>
21471
+ <a href="/bar" up-follow>Bar</a>
21472
+ </nav>
21473
+ ```
20888
21474
 
20889
21475
  By giving the navigation bar the `[up-nav]` attribute, links pointing to the current browser address are highlighted
20890
21476
  as we navigate through the site.
20891
21477
 
20892
21478
  If the current URL is `/foo`, the first link is automatically marked with an [`.up-current`](/a.up-current) class:
20893
21479
 
20894
- <nav up-nav>
20895
- <a href="/foo" up-follow class="up-current">Foo</a>
20896
- <a href="/bar" up-follow>Bar</a>
20897
- </nav>
21480
+ ```html
21481
+ <nav up-nav>
21482
+ <a href="/foo" up-follow class="up-current">Foo</a>
21483
+ <a href="/bar" up-follow>Bar</a>
21484
+ </nav>
21485
+ ```
20898
21486
 
20899
21487
  When the user clicks on the `/bar` link, the link will receive the [`up-active`](/a.up-active) class while it is waiting
20900
21488
  for the server to respond:
20901
21489
 
20902
- <nav up-nav>
20903
- <a href="/foo" up-follow class="up-current">Foo</a>
20904
- <a href="/bar" up-follow class="up-active">Bar</a>
20905
- </div>
21490
+ ```
21491
+ <nav up-nav>
21492
+ <a href="/foo" up-follow class="up-current">Foo</a>
21493
+ <a href="/bar" up-follow class="up-active">Bar</a>
21494
+ </div>
21495
+ ```
20906
21496
 
20907
21497
  Once the response is received the URL will change to `/bar` and the `up-active` class is removed:
20908
21498
 
20909
- <nav up-nav>
20910
- <a href="/foo" up-follow>Foo</a>
20911
- <a href="/bar" up-follow class="up-current">Bar</a>
20912
- </nav>
21499
+ ```html
21500
+ <nav up-nav>
21501
+ <a href="/foo" up-follow>Foo</a>
21502
+ <a href="/bar" up-follow class="up-current">Bar</a>
21503
+ </nav>
21504
+ ```
20913
21505
 
21506
+ @see [up-nav]
21507
+ @see a.up-current
21508
+ @see a.up-active
20914
21509
 
20915
21510
  @module up.feedback
20916
21511
  */
@@ -21212,7 +21807,7 @@ Once the response is received the URL will change to `/bar` and the `up-active`
21212
21807
  */
21213
21808
 
21214
21809
  /***
21215
- Links within `[up-nav]` may use the `[up-alias]` attribute to pass an [URL pattern](/url-patterns) for which they
21810
+ Links within `[up-nav]` may use the `[up-alias]` attribute to pass a [URL pattern](/url-patterns) for which they
21216
21811
  should also be highlighted as [`.up-current`](a.up-current).
21217
21812
 
21218
21813
  \#\#\# Example
@@ -21225,7 +21820,7 @@ Once the response is received the URL will change to `/bar` and the `up-active`
21225
21820
  </div>
21226
21821
  ```
21227
21822
 
21228
- To pass more than one alternative URLs, use an [URL pattern](/url-patterns).
21823
+ To pass more than one alternative URLs, use a [URL pattern](/url-patterns).
21229
21824
 
21230
21825
  @selector a[up-alias]
21231
21826
  @param up-alias
@@ -21285,8 +21880,10 @@ Once the response is received the URL will change to `/bar` and the `up-active`
21285
21880
  Passive updates
21286
21881
  ===============
21287
21882
 
21288
- This work-in-progress package will contain functionality to
21289
- passively receive updates from the server.
21883
+ This package contains functionality to passively receive updates from the server.
21884
+
21885
+ @see [up-hungry]
21886
+ @see [up-poll]
21290
21887
 
21291
21888
  @module up.radio
21292
21889
  */
@@ -21301,13 +21898,16 @@ passively receive updates from the server.
21301
21898
  Configures defaults for passive updates.
21302
21899
 
21303
21900
  @property up.radio.config
21901
+
21304
21902
  @param {Array<string>} [config.hungrySelectors]
21305
21903
  An array of CSS selectors that is replaced whenever a matching element is found in a response.
21306
21904
  These elements are replaced even when they were not targeted directly.
21307
21905
 
21308
21906
  By default this contains the [`[up-hungry]`](/up-hungry) attribute.
21907
+
21309
21908
  @param {number} [config.pollInterval=30000]
21310
21909
  The default [polling](/up-poll] interval in milliseconds.
21910
+
21311
21911
  @param {boolean|string|Function(Element)} [config.pollEnabled=true]
21312
21912
  Whether Unpoly will follow instructions to poll fragments, like the `[up-poll]` attribute.
21313
21913
 
@@ -21322,6 +21922,7 @@ passively receive updates from the server.
21322
21922
  When set to `false`, Unpoly will never allow polling.
21323
21923
 
21324
21924
  You may also pass a function that accepts the polling fragment and returns `true`, `false` or `'auto'`.
21925
+
21325
21926
  @stable
21326
21927
  */
21327
21928
  config = new up.Config(function() {
@@ -21344,9 +21945,8 @@ passively receive updates from the server.
21344
21945
  };
21345
21946
 
21346
21947
  /***
21347
- Elements with an `[up-hungry]` attribute are [updated](/up.replace) whenever there is a
21348
- matching element found in a successful response. The element is replaced even
21349
- when it isn't targeted directly.
21948
+ Elements with an `[up-hungry]` attribute are updated whenever the server
21949
+ sends a matching element, even if the element isn't targeted.
21350
21950
 
21351
21951
  Use cases for this are unread message counters or notification flashes.
21352
21952
  Such elements often live in the layout, outside of the content area that is
@@ -21438,21 +22038,27 @@ passively receive updates from the server.
21438
22038
  Assume an application layout with an unread message counter.
21439
22039
  You can use `[up-poll]` to refresh the counter every 30 seconds:
21440
22040
 
21441
- <div class="unread-count" up-poll>
21442
- 2 new messages
21443
- </div>
22041
+ ```html
22042
+ <div class="unread-count" up-poll>
22043
+ 2 new messages
22044
+ </div>
22045
+ ```
21444
22046
 
21445
22047
  \#\#\# Controlling the reload interval
21446
22048
 
21447
22049
  You may set an optional `[up-interval]` attribute to set the reload interval in milliseconds:
21448
22050
 
21449
- <div class="unread-count" up-poll up-interval="10000">
21450
- 2 new messages
21451
- </div>
22051
+ ```html
22052
+ <div class="unread-count" up-poll up-interval="10000">
22053
+ 2 new messages
22054
+ </div>
22055
+ ```
21452
22056
 
21453
22057
  If the value is omitted, a global default is used. You may configure the default like this:
21454
22058
 
21455
- up.radio.config.pollInterval = 10000
22059
+ ```js
22060
+ up.radio.config.pollInterval = 10000
22061
+ ```
21456
22062
 
21457
22063
  \#\#\# Controlling the source URL
21458
22064
 
@@ -21460,13 +22066,20 @@ passively receive updates from the server.
21460
22066
 
21461
22067
  To reload from another URL, set an `[up-source]` attribute on the polling element:
21462
22068
 
21463
- <div class="unread-count" up-poll up-source="/unread-count">
21464
- 2 new messages
21465
- </div>
22069
+ ```html
22070
+ <div class="unread-count" up-poll up-source="/unread-count">
22071
+ 2 new messages
22072
+ </div>
22073
+ ```
21466
22074
 
21467
22075
  \#\#\# Skipping updates when nothing changed
21468
22076
 
21469
- TODO: Document [up-time] and X-Up-Reload-From-Time (currently both documented in `X-Up-Reload-From-Time`).
22077
+ When polling a fragment periodically we want to avoid rendering unchanged content.
22078
+ This saves <b>CPU time</b> and reduces the <b>bandwidth cost</b> for a
22079
+ request/response exchange to **~1 KB**.
22080
+
22081
+ To achieve this we timestamp your fragments with an `[up-time]` attribute to indicate
22082
+ when the underlying data was last changed. See `[up-time]` for a detailed example.
21470
22083
 
21471
22084
  @selector [up-poll]
21472
22085
  @param [up-interval]