unpoly-rails 3.7.3.2 → 3.8.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,7 +5,7 @@
5
5
  /***/ (() => {
6
6
 
7
7
  window.up = {
8
- version: '3.7.3'
8
+ version: '3.8.0-rc1'
9
9
  };
10
10
 
11
11
 
@@ -230,11 +230,6 @@ up.util = (function () {
230
230
  function isArguments(value) {
231
231
  return Object.prototype.toString.call(value) === '[object Arguments]';
232
232
  }
233
- function nullToUndefined(value) {
234
- if (!isNull(value)) {
235
- return value;
236
- }
237
- }
238
233
  function wrapList(value) {
239
234
  if (isList(value)) {
240
235
  return value;
@@ -338,9 +333,6 @@ up.util = (function () {
338
333
  function compact(array) {
339
334
  return filterList(array, isGiven);
340
335
  }
341
- function filterMap(list, mapping) {
342
- return filterList(map(list, mapping), isDefined);
343
- }
344
336
  function compactObject(object) {
345
337
  return pickBy(object, isGiven);
346
338
  }
@@ -390,9 +382,6 @@ up.util = (function () {
390
382
  function queueTask(task) {
391
383
  return setTimeout(task);
392
384
  }
393
- function queueMicrotask(task) {
394
- return Promise.resolve().then(task);
395
- }
396
385
  function last(value) {
397
386
  return value[value.length - 1];
398
387
  }
@@ -400,6 +389,9 @@ up.util = (function () {
400
389
  let indexOf = value.indexOf || Array.prototype.indexOf;
401
390
  return indexOf.call(value, subValue) >= 0;
402
391
  }
392
+ function containsAll(values, subValues) {
393
+ return every(subValues, (subValue) => contains(values, subValue));
394
+ }
403
395
  function objectContains(object, subObject) {
404
396
  const reducedValue = pick(object, Object.keys(subObject));
405
397
  return isEqual(subObject, reducedValue);
@@ -583,6 +575,14 @@ up.util = (function () {
583
575
  function reverse(list) {
584
576
  return copy(list).reverse();
585
577
  }
578
+ function replaceValue(value, matchValue, replacementValue) {
579
+ if (value === matchValue) {
580
+ return replacementValue;
581
+ }
582
+ else {
583
+ return value;
584
+ }
585
+ }
586
586
  function renameKeys(object, renameKeyFn) {
587
587
  const renamed = {};
588
588
  for (let key in object) {
@@ -734,7 +734,6 @@ up.util = (function () {
734
734
  normalizeMethod,
735
735
  methodAllowsPayload,
736
736
  copy,
737
- copyArrayLike,
738
737
  merge,
739
738
  mergeDefined,
740
739
  options: newOptions,
@@ -748,7 +747,6 @@ up.util = (function () {
748
747
  every,
749
748
  find: findInList,
750
749
  filter: filterList,
751
- filterMap: filterMap,
752
750
  reject,
753
751
  intersect,
754
752
  compact,
@@ -780,6 +778,7 @@ up.util = (function () {
780
778
  isRegExp,
781
779
  timer: scheduleTimer,
782
780
  contains,
781
+ containsAll,
783
782
  objectContains,
784
783
  toArray,
785
784
  pick,
@@ -806,7 +805,6 @@ up.util = (function () {
806
805
  isBasicObjectProperty,
807
806
  isCrossOrigin,
808
807
  task: queueTask,
809
- microtask: queueMicrotask,
810
808
  isEqual,
811
809
  parseTokens,
812
810
  wrapList,
@@ -817,10 +815,9 @@ up.util = (function () {
817
815
  delegate: defineDelegates,
818
816
  reverse,
819
817
  camelToKebabCase,
820
- nullToUndefined,
818
+ replaceValue,
821
819
  sprintf,
822
820
  renameKeys,
823
- negate,
824
821
  memoizeMethod,
825
822
  safeStringifyJSON,
826
823
  variant,
@@ -1184,7 +1181,7 @@ up.element = (function () {
1184
1181
  }
1185
1182
  }
1186
1183
  function idSelector(id) {
1187
- if (id.match(/^[a-z0-9\-_]+$/i)) {
1184
+ if (id.match(/^[a-z][a-z0-9\-_]*$/i)) {
1188
1185
  return `#${id}`;
1189
1186
  }
1190
1187
  else {
@@ -1274,9 +1271,6 @@ up.element = (function () {
1274
1271
  element.appendChild(wrapper);
1275
1272
  return wrapper;
1276
1273
  }
1277
- function isWrapper(element) {
1278
- return element.matches('up-wrapper');
1279
- }
1280
1274
  function preservingFocus(fn) {
1281
1275
  const oldFocusElement = document.activeElement;
1282
1276
  try {
@@ -1289,7 +1283,8 @@ up.element = (function () {
1289
1283
  }
1290
1284
  }
1291
1285
  function stringAttr(element, attribute) {
1292
- return u.nullToUndefined(element.getAttribute(attribute));
1286
+ let value = element.getAttribute(attribute);
1287
+ return u.replaceValue(value, null, undefined);
1293
1288
  }
1294
1289
  function booleanAttr(element, attribute, pass) {
1295
1290
  if (!element.hasAttribute(attribute))
@@ -1314,14 +1309,15 @@ up.element = (function () {
1314
1309
  }
1315
1310
  }
1316
1311
  }
1317
- function booleanOrStringAttr(element, attribute) {
1318
- return booleanAttr(element, attribute, true);
1312
+ function booleanOrStringAttr(element, attribute, trueValue = true) {
1313
+ let value = booleanAttr(element, attribute, true);
1314
+ return value === true ? trueValue : value;
1319
1315
  }
1320
1316
  function numberAttr(element, attribute) {
1321
1317
  let value = element.getAttribute(attribute);
1322
1318
  if (value) {
1323
1319
  value = value.replace(/_/g, '');
1324
- if (value.match(/^[\d.]+$/)) {
1320
+ if (value.match(/^-?[\d.]+$/)) {
1325
1321
  return parseFloat(value);
1326
1322
  }
1327
1323
  }
@@ -1358,10 +1354,6 @@ up.element = (function () {
1358
1354
  element.classList.add(klass);
1359
1355
  return () => element.classList.remove(klass);
1360
1356
  }
1361
- function setTemporaryAttr(element, attr, value) {
1362
- element.setAttribute(attr, value);
1363
- return () => element.removeAttribute(element, attr);
1364
- }
1365
1357
  function computedStyle(element, props) {
1366
1358
  const style = window.getComputedStyle(element);
1367
1359
  return extractFromStyleObject(style, props);
@@ -1447,6 +1439,18 @@ up.element = (function () {
1447
1439
  function crossOriginSelector(attr) {
1448
1440
  return `[${attr}*="//"]:not([${attr}*="//${location.host}/"])`;
1449
1441
  }
1442
+ function isIntersectingWindow(element, { margin = 0 } = {}) {
1443
+ const rect = up.Rect.fromElement(element);
1444
+ rect.grow(margin);
1445
+ return (rect.bottom > 0) && (rect.top < window.innerHeight) &&
1446
+ (rect.right > 0) && (rect.left < window.innerWidth);
1447
+ }
1448
+ function unionSelector(includes, excludes) {
1449
+ let selector = `:is(${includes.join()})`;
1450
+ if (u.isPresent(excludes))
1451
+ selector += `:not(${excludes.join()})`;
1452
+ return selector;
1453
+ }
1450
1454
  return {
1451
1455
  subtree,
1452
1456
  contains,
@@ -1481,7 +1485,6 @@ up.element = (function () {
1481
1485
  setMissingAttr,
1482
1486
  unwrap,
1483
1487
  wrapChildren,
1484
- isWrapper,
1485
1488
  attr: stringAttr,
1486
1489
  booleanAttr,
1487
1490
  numberAttr,
@@ -1498,11 +1501,12 @@ up.element = (function () {
1498
1501
  upClasses,
1499
1502
  toggleAttr,
1500
1503
  addTemporaryClass,
1501
- setTemporaryAttr,
1502
1504
  cleanJQuery,
1503
1505
  parseSelector,
1504
1506
  isEmpty,
1505
1507
  crossOriginSelector,
1508
+ isIntersectingWindow,
1509
+ unionSelector,
1506
1510
  };
1507
1511
  })();
1508
1512
 
@@ -1612,6 +1616,7 @@ up.Record = class Record {
1612
1616
  /***/ (() => {
1613
1617
 
1614
1618
  const u = up.util;
1619
+ const e = up.element;
1615
1620
  up.Config = class Config {
1616
1621
  constructor(blueprintFn = (() => ({}))) {
1617
1622
  this._blueprintFn = blueprintFn;
@@ -1627,10 +1632,7 @@ up.Config = class Config {
1627
1632
  selector(prop) {
1628
1633
  let includes = this[prop];
1629
1634
  let excludes = this['no' + u.upperCaseFirst(prop)];
1630
- let selector = `:is(${includes.join()})`;
1631
- if (u.isPresent(excludes))
1632
- selector += `:not(${excludes.join()})`;
1633
- return selector;
1635
+ return e.unionSelector(includes, excludes);
1634
1636
  }
1635
1637
  selectorFn(prop) {
1636
1638
  return () => this.selector(prop);
@@ -1801,6 +1803,12 @@ up.Rect = class Rect extends up.Record {
1801
1803
  get right() {
1802
1804
  return this.left + this.width;
1803
1805
  }
1806
+ grow(padding) {
1807
+ this.left -= padding;
1808
+ this.top -= padding;
1809
+ this.width += padding * 2;
1810
+ this.height += padding * 2;
1811
+ }
1804
1812
  static fromElement(element) {
1805
1813
  return new (this)(element.getBoundingClientRect());
1806
1814
  }
@@ -1812,64 +1820,46 @@ up.Rect = class Rect extends up.Record {
1812
1820
  /***/ (() => {
1813
1821
 
1814
1822
  const e = up.element;
1823
+ const SHIFT_CLASS = 'up-scrollbar-away';
1815
1824
  up.BodyShifter = class BodyShifter {
1816
1825
  constructor() {
1817
- this._unshiftFns = [];
1818
1826
  this._anchoredElements = new Set();
1819
1827
  this._stack = 0;
1820
1828
  }
1821
1829
  lowerStack() {
1822
- this._stack--;
1823
- if (this._stack === 0) {
1830
+ if (--this._stack === 0)
1824
1831
  this._unshiftNow();
1825
- }
1826
1832
  }
1827
1833
  raiseStack() {
1828
- this._stack++;
1829
- if (this._stack === 1) {
1834
+ if (++this._stack === 1)
1830
1835
  this._shiftNow();
1831
- }
1832
1836
  }
1833
1837
  onAnchoredElementInserted(element) {
1834
1838
  this._anchoredElements.add(element);
1835
- if (this._isShifted()) {
1836
- this._shiftAnchoredElement(element);
1837
- }
1839
+ this._shiftElement(element, 'right');
1838
1840
  return () => this._anchoredElements.delete(element);
1839
1841
  }
1840
1842
  _isShifted() {
1841
- return this._scrollbarTookSpace && this._stack > 0;
1843
+ return this._rootScrollbarWidth && this._stack > 0;
1842
1844
  }
1843
1845
  _shiftNow() {
1844
- this._scrollbarWidth = up.viewport.scrollbarWidth();
1845
- this._scrollbarTookSpace = up.viewport.rootHasReducedWidthFromScrollbar();
1846
- if (!this._scrollbarTookSpace)
1847
- return;
1848
- this._shiftBody();
1846
+ this._rootScrollbarWidth = up.viewport.rootScrollbarWidth();
1847
+ e.root.style.setProperty('--up-scrollbar-width', this._rootScrollbarWidth + 'px');
1848
+ this._shiftElement(document.body, 'padding-right');
1849
1849
  for (let element of this._anchoredElements) {
1850
- this._shiftAnchoredElement(element);
1850
+ this._shiftElement(element, 'right');
1851
1851
  }
1852
1852
  }
1853
- _shiftBody() {
1854
- const overflowElement = up.viewport.rootOverflowElement();
1855
- this._changeStyle(overflowElement, { overflowY: 'hidden' });
1856
- const { body } = document;
1857
- const bodyRightPadding = e.styleNumber(body, 'paddingRight');
1858
- const bodyRightShift = this._scrollbarWidth + bodyRightPadding;
1859
- this._changeStyle(body, { paddingRight: bodyRightShift });
1860
- }
1861
- _shiftAnchoredElement(element) {
1862
- const elementRight = e.styleNumber(element, 'right');
1863
- const elementRightShift = this._scrollbarWidth + elementRight;
1864
- this._changeStyle(element, { right: elementRightShift });
1865
- }
1866
- _changeStyle(element, styles) {
1867
- this._unshiftFns.push(e.setTemporaryStyle(element, styles));
1853
+ _shiftElement(element, styleProp) {
1854
+ if (!this._isShifted())
1855
+ return;
1856
+ let originalValue = e.style(element, styleProp);
1857
+ element.style.setProperty('--up-original-' + styleProp, originalValue);
1858
+ element.classList.add(SHIFT_CLASS);
1868
1859
  }
1869
1860
  _unshiftNow() {
1870
- let unshiftFn;
1871
- while (unshiftFn = this._unshiftFns.pop()) {
1872
- unshiftFn();
1861
+ for (let element of [document.body, ...this._anchoredElements]) {
1862
+ element.classList.remove(SHIFT_CLASS);
1873
1863
  }
1874
1864
  }
1875
1865
  };
@@ -3078,6 +3068,7 @@ up.Change.FromContent = (_a = class FromContent extends up.Change {
3078
3068
  }
3079
3069
  this.options.title = this.improveHistoryValue(this.options.title, responseDoc.title);
3080
3070
  this.options.metaTags = this.improveHistoryValue(this.options.metaTags, responseDoc.metaTags);
3071
+ this.options.lang = this.improveHistoryValue(this.options.lang, responseDoc.lang);
3081
3072
  }
3082
3073
  _defaultPlacement() {
3083
3074
  if (!this.options.document && !this.options.fragment) {
@@ -3831,6 +3822,7 @@ var __rest = (this && this.__rest) || function (s, e) {
3831
3822
  return t;
3832
3823
  };
3833
3824
  const u = up.util;
3825
+ const e = up.element;
3834
3826
  up.FormValidator = class FormValidator {
3835
3827
  constructor(form) {
3836
3828
  this._form = form;
@@ -3891,7 +3883,7 @@ up.FormValidator = class FormValidator {
3891
3883
  }
3892
3884
  }
3893
3885
  _getTargetSelectorSolutions({ target, origin }) {
3894
- if (u.isString(target) && target) {
3886
+ if (u.isString(target)) {
3895
3887
  up.puts('up.validate()', 'Validating target "%s"', target);
3896
3888
  let simpleSelectors = up.fragment.splitTarget(target);
3897
3889
  return u.compact(simpleSelectors.map(function (simpleSelector) {
@@ -3920,7 +3912,7 @@ up.FormValidator = class FormValidator {
3920
3912
  _getValidateAttrSolutions(field) {
3921
3913
  let containerWithAttr = field.closest('[up-validate]');
3922
3914
  if (containerWithAttr) {
3923
- let target = containerWithAttr.getAttribute('up-validate');
3915
+ let target = e.booleanOrStringAttr(containerWithAttr, 'up-validate');
3924
3916
  return this._getTargetSelectorSolutions({ target, origin: field });
3925
3917
  }
3926
3918
  }
@@ -3968,7 +3960,8 @@ up.FormValidator = class FormValidator {
3968
3960
  options.guardEvent = up.event.build('up:form:validate', {
3969
3961
  fields: dirtyFields,
3970
3962
  log: 'Validating form',
3971
- params: options.params
3963
+ params: options.params,
3964
+ form: this._form,
3972
3965
  });
3973
3966
  this._rendering = true;
3974
3967
  let renderingPromise = this._nextRenderPromise;
@@ -4617,6 +4610,7 @@ up.Layer = class Layer extends up.Record {
4617
4610
  this.savedTitle = document.title;
4618
4611
  this.savedMetaTags = up.history.findMetaTags();
4619
4612
  this.savedLocation = up.history.location;
4613
+ this.savedLang = up.history.getLang();
4620
4614
  }
4621
4615
  }
4622
4616
  restoreHistory() {
@@ -4632,6 +4626,9 @@ up.Layer = class Layer extends up.Record {
4632
4626
  if (this.savedMetaTags) {
4633
4627
  up.history.updateMetaTags(this.savedMetaTags);
4634
4628
  }
4629
+ if (u.isString(this.savedLang)) {
4630
+ up.history.updateLang(this.savedLang);
4631
+ }
4635
4632
  }
4636
4633
  asCurrent(fn) {
4637
4634
  return this.stack.asCurrent(this, fn);
@@ -4648,6 +4645,9 @@ up.Layer = class Layer extends up.Record {
4648
4645
  if (u.isString(options.title)) {
4649
4646
  this.title = options.title;
4650
4647
  }
4648
+ if (u.isString(options.lang)) {
4649
+ this.lang = options.lang;
4650
+ }
4651
4651
  }
4652
4652
  showsLiveHistory() {
4653
4653
  return this.history && this.isFront();
@@ -4680,6 +4680,20 @@ up.Layer = class Layer extends up.Record {
4680
4680
  up.history.updateMetaTags(metaTags);
4681
4681
  }
4682
4682
  }
4683
+ get lang() {
4684
+ if (this.showsLiveHistory()) {
4685
+ return up.history.getLang();
4686
+ }
4687
+ else {
4688
+ return this.savedLang;
4689
+ }
4690
+ }
4691
+ set lang(lang) {
4692
+ this.savedLang = lang;
4693
+ if (this.showsLiveHistory()) {
4694
+ up.history.updateLang(lang);
4695
+ }
4696
+ }
4683
4697
  get location() {
4684
4698
  if (this.showsLiveHistory()) {
4685
4699
  return up.history.location;
@@ -5408,7 +5422,10 @@ up.LinkFeedbackURLs = class LinkFeedbackURLs {
5408
5422
  }
5409
5423
  isCurrent(normalizedLocation) {
5410
5424
  var _a, _b;
5411
- return this._isSafe && !!(this.href === normalizedLocation ||
5425
+ if (!normalizedLocation) {
5426
+ return false;
5427
+ }
5428
+ return !!(this.href === normalizedLocation ||
5412
5429
  this._upHREF === normalizedLocation ||
5413
5430
  ((_b = (_a = this._aliasPattern) === null || _a === void 0 ? void 0 : _a.test) === null || _b === void 0 ? void 0 : _b.call(_a, normalizedLocation, false)));
5414
5431
  }
@@ -5421,62 +5438,41 @@ up.LinkFeedbackURLs = class LinkFeedbackURLs {
5421
5438
 
5422
5439
  const u = up.util;
5423
5440
  const e = up.element;
5424
- up.LinkPreloader = class LinkPreloader {
5425
- watchLink(link) {
5426
- if (!up.link.preloadIssue(link)) {
5427
- this._on(link, 'mouseenter', (event) => this._considerPreload(event, true));
5428
- this._on(link, 'mousedown touchstart', (event) => this._considerPreload(event));
5429
- this._on(link, 'mouseleave', (event) => this._stopPreload(event));
5430
- }
5431
- }
5432
- _on(link, eventTypes, callback) {
5433
- up.on(link, eventTypes, { passive: true }, callback);
5434
- }
5435
- _considerPreload(event, applyDelay) {
5436
- const link = event.target;
5437
- if (link !== this._currentLink) {
5438
- this.reset();
5439
- this._currentLink = link;
5440
- if (up.link.shouldFollowEvent(event, link)) {
5441
- if (applyDelay) {
5442
- this._preloadAfterDelay(event, link);
5443
- }
5444
- else {
5445
- this._preloadNow(event, link);
5446
- }
5447
- }
5448
- }
5441
+ up.LinkFollowIntent = class LinkFollowIntent {
5442
+ constructor(link, callback) {
5443
+ this._link = link;
5444
+ this._callback = callback;
5445
+ this._on('mouseenter mousedown touchstart', (event) => this._scheduleCallback(event));
5446
+ this._on('mouseleave', () => this._unscheduleCallback());
5447
+ up.fragment.onAborted(this._link, () => this._unscheduleCallback());
5449
5448
  }
5450
- _stopPreload(event) {
5451
- if (event.target === this._currentLink) {
5452
- return this.reset();
5453
- }
5449
+ _on(eventType, callback) {
5450
+ up.on(this._link, eventType, { passive: true }, callback);
5454
5451
  }
5455
- reset() {
5456
- var _a;
5457
- if (!this._currentLink) {
5452
+ _scheduleCallback(event) {
5453
+ if (!up.link.shouldFollowEvent(event, this._link))
5458
5454
  return;
5455
+ this._unscheduleCallback();
5456
+ const applyDelay = (event.type === 'mouseenter');
5457
+ if (applyDelay) {
5458
+ let delay = this._parseDelay();
5459
+ this._timer = u.timer(delay, () => this._runCallback(event));
5459
5460
  }
5460
- clearTimeout(this._timer);
5461
- if ((_a = this._currentRequest) === null || _a === void 0 ? void 0 : _a.background) {
5462
- this._currentRequest.abort();
5461
+ else {
5462
+ this._runCallback(event);
5463
5463
  }
5464
- this._currentLink = undefined;
5465
- this._currentRequest = undefined;
5466
5464
  }
5467
- _preloadAfterDelay(event, link) {
5465
+ _unscheduleCallback() {
5466
+ clearTimeout(this._timer);
5467
+ up.network.abort((request) => (request.origin === this._link) && request.background);
5468
+ }
5469
+ _parseDelay() {
5468
5470
  var _a;
5469
- const delay = (_a = e.numberAttr(link, 'up-preload-delay')) !== null && _a !== void 0 ? _a : up.link.config.preloadDelay;
5470
- this._timer = u.timer(delay, () => this._preloadNow(event, link));
5471
+ return (_a = e.numberAttr(this._link, 'up-preload-delay')) !== null && _a !== void 0 ? _a : up.link.config.preloadDelay;
5471
5472
  }
5472
- _preloadNow(event, link) {
5473
- if (!link.isConnected) {
5474
- this.reset();
5475
- return;
5476
- }
5477
- const onQueued = request => { return this._currentRequest = request; };
5473
+ _runCallback(event) {
5478
5474
  up.log.putsEvent(event);
5479
- up.error.muteUncriticalRejection(up.link.preload(link, { onQueued }));
5475
+ up.error.muteUncriticalRejection(this._callback());
5480
5476
  }
5481
5477
  };
5482
5478
 
@@ -6236,7 +6232,6 @@ up.Request = (_a = class Request extends up.Record {
6236
6232
  'wrapMethod',
6237
6233
  'contentType',
6238
6234
  'payload',
6239
- 'onQueued',
6240
6235
  'onLoading',
6241
6236
  'fail',
6242
6237
  'abortable',
@@ -6271,7 +6266,7 @@ up.Request = (_a = class Request extends up.Record {
6271
6266
  }
6272
6267
  this.deferred = u.newDeferred();
6273
6268
  (_d = this.badResponseTime) !== null && _d !== void 0 ? _d : (this.badResponseTime = u.evalOption(up.network.config.badResponseTime, this));
6274
- this._addAutoHeaders();
6269
+ this._setAutoHeaders();
6275
6270
  }
6276
6271
  get xhr() {
6277
6272
  var _b;
@@ -6281,7 +6276,7 @@ up.Request = (_a = class Request extends up.Record {
6281
6276
  if (this._fragments) {
6282
6277
  return this._fragments;
6283
6278
  }
6284
- else if (this.target) {
6279
+ else {
6285
6280
  let steps = up.fragment.parseTargetSteps(this.target);
6286
6281
  let selectors = u.map(steps, 'selector');
6287
6282
  let lookupOpts = { origin: this.origin, layer: this.layer };
@@ -6337,9 +6332,7 @@ up.Request = (_a = class Request extends up.Record {
6337
6332
  return u.evalAutoOption(this.cache, up.network.config.autoCache, this);
6338
6333
  }
6339
6334
  runQueuedCallbacks() {
6340
- var _b;
6341
6335
  u.always(this, () => this._evictExpensiveAttrs());
6342
- (_b = this.onQueued) === null || _b === void 0 ? void 0 : _b.call(this, this);
6343
6336
  }
6344
6337
  load() {
6345
6338
  var _b;
@@ -6484,9 +6477,6 @@ up.Request = (_a = class Request extends up.Record {
6484
6477
  return this.method + ' ' + this.url;
6485
6478
  }
6486
6479
  isPartOfSubtree(subtreeElements) {
6487
- if (!this.fragments || !subtreeElements) {
6488
- return false;
6489
- }
6490
6480
  subtreeElements = u.wrapList(subtreeElements);
6491
6481
  return u.some(this.fragments, function (fragment) {
6492
6482
  return u.some(subtreeElements, (subtreeElement) => subtreeElement.contains(fragment));
@@ -6498,17 +6488,20 @@ up.Request = (_a = class Request extends up.Record {
6498
6488
  header(name) {
6499
6489
  return this.headers[name];
6500
6490
  }
6501
- _addAutoHeaders() {
6491
+ _setAutoHeaders() {
6502
6492
  for (let key of ['target', 'failTarget', 'mode', 'failMode', 'context', 'failContext']) {
6503
- this._addAutoHeader(up.protocol.headerize(key), this[key]);
6493
+ this._setPropertyHeader(key);
6504
6494
  }
6505
6495
  let csrfHeader, csrfToken;
6506
6496
  if ((csrfHeader = this.csrfHeader()) && (csrfToken = this.csrfToken())) {
6507
- this._addAutoHeader(csrfHeader, csrfToken);
6497
+ this._setAutoHeader(csrfHeader, csrfToken);
6508
6498
  }
6509
- this._addAutoHeader(up.protocol.headerize('version'), up.version);
6499
+ this._setAutoHeader(up.protocol.headerize('version'), up.version);
6500
+ }
6501
+ _setPropertyHeader(key) {
6502
+ this._setAutoHeader(up.protocol.headerize(key), this[key]);
6510
6503
  }
6511
- _addAutoHeader(name, value) {
6504
+ _setAutoHeader(name, value) {
6512
6505
  if (u.isMissing(value)) {
6513
6506
  return;
6514
6507
  }
@@ -6517,6 +6510,16 @@ up.Request = (_a = class Request extends up.Record {
6517
6510
  }
6518
6511
  this.headers[name] = value;
6519
6512
  }
6513
+ mergeIfUnsent(trackingRequest) {
6514
+ if (this.state !== 'new')
6515
+ return;
6516
+ if (!this.target || !trackingRequest.target)
6517
+ return;
6518
+ let targetAtoms = up.fragment.splitTarget(this.target + ',' + trackingRequest.target);
6519
+ this.target = u.uniq(targetAtoms).join(', ');
6520
+ this._setPropertyHeader('target');
6521
+ this._fragments = u.uniq([...this.fragments, ...trackingRequest.fragments]);
6522
+ }
6520
6523
  static tester(condition, { except } = {}) {
6521
6524
  let testFn;
6522
6525
  if (u.isFunction(condition)) {
@@ -6560,78 +6563,85 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
6560
6563
  });
6561
6564
  };
6562
6565
  const u = up.util;
6566
+ class Route {
6567
+ constructor() {
6568
+ this.varyHeaders = new Set();
6569
+ this.requests = [];
6570
+ }
6571
+ matchBest(newRequest) {
6572
+ let matches = this.requests.filter((cachedRequest) => this.satisfies(cachedRequest, newRequest));
6573
+ return u.last(matches);
6574
+ }
6575
+ delete(request) {
6576
+ u.remove(this.requests, request);
6577
+ }
6578
+ put(request) {
6579
+ this.requests.push(request);
6580
+ }
6581
+ updateVary(response) {
6582
+ for (let headerName of response.varyHeaderNames) {
6583
+ this.varyHeaders.add(headerName);
6584
+ }
6585
+ }
6586
+ satisfies(cachedRequest, newRequest) {
6587
+ if (cachedRequest === newRequest)
6588
+ return true;
6589
+ return u.every(this.varyHeaders, (varyHeader) => {
6590
+ let cachedValue = cachedRequest.header(varyHeader);
6591
+ let newValue = newRequest.header(varyHeader);
6592
+ if (varyHeader === 'X-Up-Target' || varyHeader === 'X-Up-Fail-Target') {
6593
+ if (!cachedValue)
6594
+ return true;
6595
+ if (!newValue)
6596
+ return false;
6597
+ let cachedTokens = u.parseTokens(cachedValue, { separator: 'comma' });
6598
+ let newTokens = u.parseTokens(newValue, { separator: 'comma' });
6599
+ return u.containsAll(cachedTokens, newTokens);
6600
+ }
6601
+ else {
6602
+ return cachedValue === newValue;
6603
+ }
6604
+ });
6605
+ }
6606
+ }
6563
6607
  up.Request.Cache = class Cache {
6564
6608
  constructor() {
6565
6609
  this.reset();
6566
6610
  }
6567
6611
  reset() {
6568
- this._varyInfo = {};
6569
- this._map = new Map();
6570
- }
6571
- _cacheKey(request) {
6572
- let influencingHeaders = this._getPreviousInfluencingHeaders(request);
6573
- let varyPart = u.flatMap(influencingHeaders, (headerName) => [headerName, request.header(headerName)]);
6574
- return [request.description, ...varyPart].join(':');
6575
- }
6576
- _getPreviousInfluencingHeaders(request) {
6577
- var _a, _b;
6578
- return ((_a = this._varyInfo)[_b = request.description] || (_a[_b] = new Set()));
6612
+ this._routes = {};
6613
+ this._requests = [];
6579
6614
  }
6580
6615
  get(request) {
6581
6616
  request = this._wrap(request);
6582
- let cacheKey = this._cacheKey(request);
6583
- let cachedRequest = this._map.get(cacheKey);
6617
+ let route = this._getRoute(request);
6618
+ let cachedRequest = route.matchBest(request);
6584
6619
  if (cachedRequest) {
6585
6620
  if (this._isUsable(cachedRequest)) {
6586
6621
  return cachedRequest;
6587
6622
  }
6588
6623
  else {
6589
- this._map.delete(cacheKey);
6624
+ this._delete(request, route);
6590
6625
  }
6591
6626
  }
6592
6627
  }
6593
- get _capacity() {
6594
- return up.network.config.cacheSize;
6595
- }
6596
- _isUsable(request) {
6597
- return request.age < up.network.config.cacheEvictAge;
6598
- }
6599
6628
  put(request) {
6600
6629
  return __awaiter(this, void 0, void 0, function* () {
6601
6630
  request = this._wrap(request);
6602
- this._makeRoom();
6603
- let cacheKey = this._updateCacheKey(request);
6604
- this._map.set(cacheKey, request);
6631
+ let route = this._getRoute(request);
6632
+ let { response } = request;
6633
+ if (response)
6634
+ route.updateVary(response);
6635
+ let superseded = route.requests.filter((oldRequest) => route.satisfies(request, oldRequest));
6636
+ for (let r of superseded) {
6637
+ this._delete(r);
6638
+ }
6639
+ request.cacheRoute = route;
6640
+ route.put(request);
6641
+ this._requests.push(request);
6642
+ this._limitSize();
6605
6643
  });
6606
6644
  }
6607
- _updateCacheKey(request) {
6608
- let oldCacheKey = this._cacheKey(request);
6609
- let { response } = request;
6610
- if (response) {
6611
- this._mergePreviousHeaderNames(request, response);
6612
- let newCacheKey = this._cacheKey(request);
6613
- this._renameMapKey(oldCacheKey, newCacheKey);
6614
- return newCacheKey;
6615
- }
6616
- else {
6617
- return oldCacheKey;
6618
- }
6619
- }
6620
- _renameMapKey(oldKey, newKey) {
6621
- if (oldKey !== newKey && this._map.has(oldKey)) {
6622
- this._map.set(newKey, this._map.get(oldKey));
6623
- this._map.delete(oldKey);
6624
- }
6625
- }
6626
- _mergePreviousHeaderNames(request, response) {
6627
- let headersInfluencingResponse = response.ownInfluncingHeaders;
6628
- if (headersInfluencingResponse.length) {
6629
- let previousInfluencingHeaders = this._getPreviousInfluencingHeaders(request);
6630
- for (let headerName of headersInfluencingResponse) {
6631
- previousInfluencingHeaders.add(headerName);
6632
- }
6633
- }
6634
- }
6635
6645
  alias(existingCachedRequest, newRequest) {
6636
6646
  existingCachedRequest = this.get(existingCachedRequest);
6637
6647
  if (!existingCachedRequest)
@@ -6648,7 +6658,7 @@ up.Request.Cache = class Cache {
6648
6658
  newRequest.state = 'tracking';
6649
6659
  let value = yield u.always(existingRequest);
6650
6660
  if (value instanceof up.Response) {
6651
- if (options.force || this._isCacheCompatible(existingRequest, newRequest)) {
6661
+ if (options.force || existingRequest.cacheRoute.satisfies(existingRequest, newRequest)) {
6652
6662
  newRequest.fromCache = true;
6653
6663
  value = u.variant(value, { request: newRequest });
6654
6664
  newRequest.respondWith(value);
@@ -6669,31 +6679,45 @@ up.Request.Cache = class Cache {
6669
6679
  willHaveSameResponse(existingRequest, newRequest) {
6670
6680
  return existingRequest === newRequest || existingRequest === newRequest.trackedRequest;
6671
6681
  }
6672
- _delete(request) {
6673
- request = this._wrap(request);
6674
- let cacheKey = this._cacheKey(request);
6675
- this._map.delete(cacheKey);
6676
- }
6677
6682
  evict(condition = true, testerOptions) {
6678
6683
  this._eachMatch(condition, testerOptions, (request) => this._delete(request));
6679
6684
  }
6680
6685
  expire(condition = true, testerOptions) {
6681
6686
  this._eachMatch(condition, testerOptions, (request) => request.expired = true);
6682
6687
  }
6683
- _makeRoom() {
6684
- while (this._map.size >= this._capacity) {
6685
- let oldestKey = this._map.keys().next().value;
6686
- this._map.delete(oldestKey);
6688
+ reindex(request) {
6689
+ this._delete(request);
6690
+ this.put(request);
6691
+ }
6692
+ _delete(request) {
6693
+ var _a;
6694
+ u.remove(this._requests, request);
6695
+ (_a = request.cacheRoute) === null || _a === void 0 ? void 0 : _a.delete(request);
6696
+ delete request.cacheRoute;
6697
+ }
6698
+ _getRoute(request) {
6699
+ var _a, _b;
6700
+ return request.cacheRoute || ((_a = this._routes)[_b = request.description] || (_a[_b] = new Route()));
6701
+ }
6702
+ _isUsable(request) {
6703
+ return request.age < up.network.config.cacheEvictAge;
6704
+ }
6705
+ get _size() {
6706
+ return this._requests.length;
6707
+ }
6708
+ get _capacity() {
6709
+ return up.network.config.cacheSize;
6710
+ }
6711
+ _limitSize() {
6712
+ for (let i = 0; i < (this._size - this._capacity); i++) {
6713
+ this._delete(this._requests[0]);
6687
6714
  }
6688
6715
  }
6689
6716
  _eachMatch(condition = true, testerOptions, fn) {
6690
6717
  let tester = up.Request.tester(condition, testerOptions);
6691
- let results = u.filter(this._map.values(), tester);
6718
+ let results = u.filter(this._requests, tester);
6692
6719
  u.each(results, fn);
6693
6720
  }
6694
- _isCacheCompatible(request1, request2) {
6695
- return this._cacheKey(request1) === this._cacheKey(request2);
6696
- }
6697
6721
  _wrap(requestOrOptions) {
6698
6722
  return u.wrapValue(up.Request, requestOrOptions);
6699
6723
  }
@@ -6722,7 +6746,7 @@ up.Request.Queue = class Queue {
6722
6746
  u.always(request, responseOrError => this._onRequestSettled(request, responseOrError));
6723
6747
  this._scheduleSlowTimer(request);
6724
6748
  this._queueRequest(request);
6725
- u.microtask(() => this._poke());
6749
+ queueMicrotask(() => this._poke());
6726
6750
  }
6727
6751
  promoteToForeground(request) {
6728
6752
  if (request.background) {
@@ -6763,7 +6787,7 @@ up.Request.Queue = class Queue {
6763
6787
  up.network.registerAliasForRedirect(request, responseOrError);
6764
6788
  }
6765
6789
  this._checkLate();
6766
- u.microtask(() => this._poke());
6790
+ queueMicrotask(() => this._poke());
6767
6791
  }
6768
6792
  _poke() {
6769
6793
  let request;
@@ -6959,16 +6983,13 @@ up.Response = class Response extends up.Record {
6959
6983
  get none() {
6960
6984
  return !this.text;
6961
6985
  }
6962
- isCacheable() {
6963
- return this.ok && !this.none;
6964
- }
6965
6986
  header(name) {
6966
6987
  var _a;
6967
6988
  return this.headers[name] || ((_a = this.xhr) === null || _a === void 0 ? void 0 : _a.getResponseHeader(name));
6968
6989
  }
6969
- get ownInfluncingHeaders() {
6970
- let influencingHeaders = up.protocol.influencingHeadersFromResponse(this);
6971
- return u.filter(influencingHeaders, (headerName) => this.request.header(headerName));
6990
+ get varyHeaderNames() {
6991
+ let varyHeaderValue = this.header('Vary');
6992
+ return u.parseTokens(varyHeaderValue, { separator: 'comma' });
6972
6993
  }
6973
6994
  get contentType() {
6974
6995
  return this.header('Content-Type');
@@ -7009,6 +7030,7 @@ up.Response = class Response extends up.Record {
7009
7030
  var _a;
7010
7031
  const u = up.util;
7011
7032
  const e = up.element;
7033
+ const FULL_DOCUMENT_PATTERN = /^\s*<(html|!DOCTYPE)\b/i;
7012
7034
  up.ResponseDoc = (_a = class ResponseDoc {
7013
7035
  constructor({ document, fragment, content, target, origin, cspNonces, match }) {
7014
7036
  if (document) {
@@ -7029,43 +7051,43 @@ up.ResponseDoc = (_a = class ResponseDoc {
7029
7051
  }
7030
7052
  this._match = match;
7031
7053
  }
7032
- _parseDocument(document) {
7033
- document = this._parse(document, e.createBrokenDocumentFromHTML);
7034
- this._isDocumentBroken = true;
7035
- this._useParseResult(document);
7036
- }
7037
- _parseFragment(fragment) {
7038
- fragment = this._parse(fragment, e.createFromHTML);
7039
- this._useParseResult(fragment);
7040
- }
7041
- _parseContent(content, target) {
7042
- if (!target)
7043
- up.fail("must pass a { target } when passing { content }");
7044
- target = u.map(up.fragment.parseTargetSteps(target), 'selector').join();
7045
- const matchingElement = e.createFromSelector(target);
7046
- if (u.isString(content)) {
7047
- matchingElement.innerHTML = content;
7054
+ _parseDocument(value) {
7055
+ if (value instanceof Document) {
7056
+ this._document = value;
7057
+ this._isFullDocument = true;
7058
+ }
7059
+ else if (u.isString(value)) {
7060
+ this._document = e.createBrokenDocumentFromHTML(value);
7061
+ this._isFullDocument = FULL_DOCUMENT_PATTERN.test(value);
7062
+ this._isDocumentBroken = true;
7048
7063
  }
7049
7064
  else {
7050
- matchingElement.appendChild(content);
7065
+ this._document = this._buildFauxDocument(value);
7066
+ this._isFullDocument = value.matches('html');
7051
7067
  }
7052
- this._useParseResult(matchingElement);
7053
7068
  }
7054
- _parse(value, parseFn) {
7055
- if (u.isString(value)) {
7056
- value = parseFn(value);
7057
- }
7058
- return value;
7069
+ _parseFragment(value) {
7070
+ let parsed = u.isString(value) ? e.createFromHTML(value) : value;
7071
+ this._document = this._buildFauxDocument(parsed);
7059
7072
  }
7060
- _useParseResult(node) {
7061
- if (node instanceof Document) {
7062
- this._document = node;
7073
+ _parseContent(value, target) {
7074
+ if (!target)
7075
+ up.fail("must pass a { target } when passing { content }");
7076
+ let simplifiedTarget = u.map(up.fragment.parseTargetSteps(target), 'selector').join();
7077
+ const matchingElement = e.createFromSelector(simplifiedTarget);
7078
+ if (u.isString(value)) {
7079
+ matchingElement.innerHTML = value;
7063
7080
  }
7064
7081
  else {
7065
- this._document = document.createElement('up-document');
7066
- this._document.append(node);
7067
- this._document.documentElement = node;
7082
+ matchingElement.appendChild(value);
7068
7083
  }
7084
+ this._document = this._buildFauxDocument(matchingElement);
7085
+ }
7086
+ _buildFauxDocument(node) {
7087
+ let fauxDocument = document.createElement('up-document');
7088
+ fauxDocument.append(node);
7089
+ fauxDocument.documentElement = node;
7090
+ return fauxDocument;
7069
7091
  }
7070
7092
  rootSelector() {
7071
7093
  return up.fragment.toTarget(this._document.documentElement);
@@ -7074,9 +7096,8 @@ up.ResponseDoc = (_a = class ResponseDoc {
7074
7096
  return this._fromHead(this._getTitleText);
7075
7097
  }
7076
7098
  _getHead() {
7077
- let { head } = this._document;
7078
- if (head && head.childNodes.length > 0) {
7079
- return head;
7099
+ if (this._isFullDocument) {
7100
+ return this._document.head;
7080
7101
  }
7081
7102
  }
7082
7103
  _fromHead(fn) {
@@ -7089,6 +7110,11 @@ up.ResponseDoc = (_a = class ResponseDoc {
7089
7110
  get assets() {
7090
7111
  return this._fromHead(up.script.findAssets);
7091
7112
  }
7113
+ get lang() {
7114
+ if (this._isFullDocument) {
7115
+ return up.history.getLang(this._document);
7116
+ }
7117
+ }
7092
7118
  _getTitleText(head) {
7093
7119
  var _b;
7094
7120
  return (_b = head.querySelector('title')) === null || _b === void 0 ? void 0 : _b.textContent;
@@ -7188,7 +7214,7 @@ up.RevealMotion = class RevealMotion {
7188
7214
  const maxPixels = u.evalOption(this._max, this._element);
7189
7215
  elementRect.height = Math.min(elementRect.height, maxPixels);
7190
7216
  }
7191
- this._addPadding(elementRect);
7217
+ elementRect.grow(this._padding);
7192
7218
  this._substractObstructions(viewportRect);
7193
7219
  if (viewportRect.height < 0) {
7194
7220
  up.fail('Viewport has no visible area');
@@ -7227,10 +7253,6 @@ up.RevealMotion = class RevealMotion {
7227
7253
  return up.Rect.fromElement(this._viewport);
7228
7254
  }
7229
7255
  }
7230
- _addPadding(elementRect) {
7231
- elementRect.top -= this._padding;
7232
- elementRect.height += 2 * this._padding;
7233
- }
7234
7256
  _selectObstructions(selector) {
7235
7257
  let elements = up.fragment.all(selector, { layer: this._obstructionsLayer });
7236
7258
  return u.filter(elements, e.isVisible);
@@ -7783,10 +7805,6 @@ up.protocol = (function () {
7783
7805
  function locationFromXHR(xhr) {
7784
7806
  return extractHeader(xhr, 'location') || xhr.responseURL;
7785
7807
  }
7786
- function influencingHeadersFromResponse(response) {
7787
- let varyHeaderValue = response.header('Vary');
7788
- return u.parseTokens(varyHeaderValue, { separator: 'comma' });
7789
- }
7790
7808
  const config = new up.Config(() => ({
7791
7809
  methodParam: '_method',
7792
7810
  csrfParam() { return e.metaContent('csrf-param'); },
@@ -7847,7 +7865,6 @@ up.protocol = (function () {
7847
7865
  headerize,
7848
7866
  wrapMethod,
7849
7867
  cspNoncesFromHeader,
7850
- influencingHeadersFromResponse,
7851
7868
  };
7852
7869
  })();
7853
7870
 
@@ -7983,44 +8000,61 @@ up.script = (function () {
7983
8000
  let registeredCompilers = [];
7984
8001
  let registeredMacros = [];
7985
8002
  function registerCompiler(...args) {
7986
- const compiler = buildCompiler(args);
7987
- return insertCompiler(registeredCompilers, compiler);
8003
+ registerProcessor(args);
7988
8004
  }
7989
8005
  function registerMacro(...args) {
7990
- const macro = buildCompiler(args);
7991
- if (up.framework.evaling) {
7992
- macro.priority || (macro.priority = detectSystemMacroPriority(macro.selector) ||
7993
- up.fail('Unregistered priority for system macro %o', macro.selector));
7994
- }
7995
- return insertCompiler(registeredMacros, macro);
8006
+ registerProcessor(args, { macro: true });
8007
+ }
8008
+ function registerAttrCompiler(...args) {
8009
+ let [attr, options, valueCallback] = parseProcessorArgs(args);
8010
+ let selector = `[${attr}]`;
8011
+ let callback = (element) => {
8012
+ let value = e.booleanOrStringAttr(element, attr, options.defaultValue);
8013
+ if (!value)
8014
+ return;
8015
+ return valueCallback(element, value);
8016
+ };
8017
+ registerProcessor([selector, options, callback]);
7996
8018
  }
7997
8019
  function detectSystemMacroPriority(macroSelector) {
7998
8020
  macroSelector = u.evalOption(macroSelector);
7999
8021
  for (let substr in SYSTEM_MACRO_PRIORITIES) {
8000
- const priority = SYSTEM_MACRO_PRIORITIES[substr];
8001
8022
  if (macroSelector.indexOf(substr) >= 0) {
8002
- return priority;
8023
+ return SYSTEM_MACRO_PRIORITIES[substr];
8024
+ }
8025
+ }
8026
+ up.fail('Unregistered priority for system macro %o', macroSelector);
8027
+ }
8028
+ function registerProcessor(args, overrides = {}) {
8029
+ let processor = buildProcessor(args, overrides);
8030
+ if (processor.macro) {
8031
+ if (up.framework.evaling) {
8032
+ processor.priority || (processor.priority = detectSystemMacroPriority(processor.selector));
8003
8033
  }
8034
+ insertProcessor(registeredMacros, processor);
8035
+ }
8036
+ else {
8037
+ insertProcessor(registeredCompilers, processor);
8004
8038
  }
8005
8039
  }
8006
- const parseCompilerArgs = function (args) {
8040
+ const parseProcessorArgs = function (args) {
8007
8041
  const defaults = u.extractOptions(args);
8008
8042
  const selector = args.shift();
8009
8043
  const callback = args.pop();
8010
8044
  const options = Object.assign(Object.assign({}, defaults), u.extractOptions(args));
8011
8045
  return [selector, options, callback];
8012
8046
  };
8013
- function buildCompiler(args) {
8014
- let [selector, options, callback] = parseCompilerArgs(args);
8047
+ function buildProcessor(args, overrides) {
8048
+ let [selector, options, callback] = parseProcessorArgs(args);
8015
8049
  options = u.options(options, {
8016
8050
  selector,
8017
8051
  isDefault: up.framework.evaling,
8018
8052
  priority: 0,
8019
8053
  batch: false,
8020
8054
  });
8021
- return Object.assign(callback, options);
8055
+ return Object.assign(callback, options, overrides);
8022
8056
  }
8023
- function insertCompiler(queue, newCompiler) {
8057
+ function insertProcessor(queue, newCompiler) {
8024
8058
  let existingCompiler;
8025
8059
  let index = 0;
8026
8060
  while ((existingCompiler = queue[index]) && (existingCompiler.priority >= newCompiler.priority)) {
@@ -8114,6 +8148,7 @@ up.script = (function () {
8114
8148
  config,
8115
8149
  compiler: registerCompiler,
8116
8150
  macro: registerMacro,
8151
+ attrCompiler: registerAttrCompiler,
8117
8152
  destructor: registerDestructor,
8118
8153
  hello,
8119
8154
  clean,
@@ -8128,6 +8163,7 @@ up.destructor = up.script.destructor;
8128
8163
  up.macro = up.script.macro;
8129
8164
  up.data = up.script.data;
8130
8165
  up.hello = up.script.hello;
8166
+ up.attribute = up.script.attrCompiler;
8131
8167
 
8132
8168
 
8133
8169
  /***/ }),
@@ -8270,6 +8306,15 @@ up.history = (function () {
8270
8306
  document.head.append(newMetaTag);
8271
8307
  }
8272
8308
  }
8309
+ function getLang(doc = document) {
8310
+ let { documentElement } = doc;
8311
+ if (documentElement.matches('html')) {
8312
+ return doc.documentElement.lang;
8313
+ }
8314
+ }
8315
+ function updateLang(newLang) {
8316
+ e.toggleAttr(e.root, 'lang', newLang, !!newLang);
8317
+ }
8273
8318
  up.macro('a[up-back], [up-href][up-back]', function (link) {
8274
8319
  if (previousLocation) {
8275
8320
  e.setMissingAttrs(link, {
@@ -8291,6 +8336,8 @@ up.history = (function () {
8291
8336
  isLocation,
8292
8337
  findMetaTags,
8293
8338
  updateMetaTags,
8339
+ getLang,
8340
+ updateLang,
8294
8341
  };
8295
8342
  })();
8296
8343
 
@@ -8773,6 +8820,25 @@ up.fragment = (function () {
8773
8820
  up.destructor(fragment, unsubscribe);
8774
8821
  return unsubscribe;
8775
8822
  }
8823
+ function onFirstIntersect(origin, callback, { margin = 0 } = {}) {
8824
+ if (e.isIntersectingWindow(origin, { margin })) {
8825
+ callback();
8826
+ return;
8827
+ }
8828
+ function processIntersectEntries(entries) {
8829
+ for (let entry of entries) {
8830
+ if (entry.isIntersecting) {
8831
+ disconnect();
8832
+ callback();
8833
+ return;
8834
+ }
8835
+ }
8836
+ }
8837
+ let observer = new IntersectionObserver(processIntersectEntries, { rootMargin: `${margin}px` });
8838
+ let disconnect = () => observer.disconnect();
8839
+ observer.observe(origin);
8840
+ onAborted(origin, disconnect);
8841
+ }
8776
8842
  up.on('up:framework:boot', function () {
8777
8843
  const { documentElement } = document;
8778
8844
  documentElement.setAttribute('up-source', u.normalizeURL(location.href, { hash: false }));
@@ -8813,6 +8879,7 @@ up.fragment = (function () {
8813
8879
  shouldRevalidate,
8814
8880
  abort,
8815
8881
  onAborted,
8882
+ onFirstIntersect,
8816
8883
  splitTarget,
8817
8884
  parseTargetSteps,
8818
8885
  isAlive,
@@ -8942,33 +9009,9 @@ up.viewport = (function () {
8942
9009
  function isRoot(element) {
8943
9010
  return element === getRoot();
8944
9011
  }
8945
- function rootHasReducedWidthFromScrollbar() {
8946
- return window.innerWidth > document.documentElement.offsetWidth;
8947
- }
8948
- function rootOverflowElement() {
8949
- const { body } = document;
8950
- const html = document.documentElement;
8951
- const element = u.find([html, body], wasChosenAsOverflowingElement);
8952
- return element || getRoot();
8953
- }
8954
- function wasChosenAsOverflowingElement(element) {
8955
- const overflowY = e.style(element, 'overflow-y');
8956
- return overflowY === 'auto' || overflowY === 'scroll';
8957
- }
8958
- const scrollbarWidth = u.memoize(function () {
8959
- const outerStyle = {
8960
- position: 'absolute',
8961
- top: '0',
8962
- left: '0',
8963
- width: '100px',
8964
- height: '100px',
8965
- overflowY: 'scroll'
8966
- };
8967
- const outer = up.element.affix(document.body, '[up-viewport]', { style: outerStyle });
8968
- const width = outer.offsetWidth - outer.clientWidth;
8969
- outer.remove();
8970
- return width;
8971
- });
9012
+ function rootScrollbarWidth() {
9013
+ return window.innerWidth - rootWidth();
9014
+ }
8972
9015
  function scrollTopKey(viewport) {
8973
9016
  return up.fragment.tryToTarget(viewport);
8974
9017
  }
@@ -9146,10 +9189,8 @@ up.viewport = (function () {
9146
9189
  get root() { return getRoot(); },
9147
9190
  rootWidth,
9148
9191
  rootHeight,
9149
- rootHasReducedWidthFromScrollbar,
9150
- rootOverflowElement,
9151
9192
  isRoot,
9152
- scrollbarWidth,
9193
+ rootScrollbarWidth,
9153
9194
  saveScroll,
9154
9195
  restoreScroll,
9155
9196
  resetScroll,
@@ -9239,8 +9280,9 @@ up.motion = (function () {
9239
9280
  return cssTransition.start();
9240
9281
  }
9241
9282
  function applyConfig(options) {
9242
- options.easing || (options.easing = config.easing);
9243
- options.duration || (options.duration = config.duration);
9283
+ var _a, _b;
9284
+ (_a = options.easing) !== null && _a !== void 0 ? _a : (options.easing = config.easing);
9285
+ (_b = options.duration) !== null && _b !== void 0 ? _b : (options.duration = config.duration);
9244
9286
  }
9245
9287
  function findNamedAnimation(name) {
9246
9288
  return namedAnimations[name] || up.fail("Unknown animation %o", name);
@@ -9510,6 +9552,7 @@ up.network = (function () {
9510
9552
  if (!newRequest.background) {
9511
9553
  queue.promoteToForeground(cachedRequest);
9512
9554
  }
9555
+ cachedRequest.mergeIfUnsent(newRequest);
9513
9556
  cache.track(cachedRequest, newRequest, { onIncompatible: processRequest });
9514
9557
  return true;
9515
9558
  }
@@ -9522,10 +9565,10 @@ up.network = (function () {
9522
9565
  function handleCaching(request) {
9523
9566
  if (request.willCache()) {
9524
9567
  cache.put(request);
9525
- request.onLoading = () => cache.put(request);
9568
+ request.onLoading = () => cache.reindex(request);
9526
9569
  }
9527
9570
  u.always(request, function (responseOrError) {
9528
- var _a, _b, _c, _d, _e;
9571
+ var _a, _b, _c, _d;
9529
9572
  let expireCache = (_b = (_a = responseOrError.expireCache) !== null && _a !== void 0 ? _a : request.expireCache) !== null && _b !== void 0 ? _b : u.evalOption(config.expireCache, request, responseOrError);
9530
9573
  if (expireCache) {
9531
9574
  cache.expire(expireCache, { except: request });
@@ -9534,12 +9577,21 @@ up.network = (function () {
9534
9577
  if (evictCache) {
9535
9578
  cache.evict(evictCache, { except: request });
9536
9579
  }
9537
- if (cache.get(request)) {
9538
- cache.put(request);
9580
+ let hasCacheEntry = cache.get(request);
9581
+ let isResponse = responseOrError instanceof up.Response;
9582
+ let isNetworkError = !isResponse;
9583
+ let isSuccessResponse = isResponse && responseOrError.ok;
9584
+ let isErrorResponse = isResponse && !responseOrError.ok;
9585
+ let isEmptyResponse = isResponse && responseOrError.none;
9586
+ if (isErrorResponse) {
9587
+ cache.evict(request.url);
9539
9588
  }
9540
- if (!((_e = responseOrError.isCacheable) === null || _e === void 0 ? void 0 : _e.call(responseOrError))) {
9589
+ else if (isNetworkError || isEmptyResponse) {
9541
9590
  cache.evict(request);
9542
9591
  }
9592
+ else if (isSuccessResponse && hasCacheEntry) {
9593
+ cache.put(request);
9594
+ }
9543
9595
  });
9544
9596
  }
9545
9597
  function isBusy() {
@@ -9557,7 +9609,8 @@ up.network = (function () {
9557
9609
  if (request.cache && response.url && request.url !== response.url) {
9558
9610
  const newRequest = u.variant(request, {
9559
9611
  method: response.method,
9560
- url: response.url
9612
+ url: response.url,
9613
+ cacheRoute: null,
9561
9614
  });
9562
9615
  cache.alias(request, newRequest);
9563
9616
  }
@@ -9864,7 +9917,6 @@ __webpack_require__(96);
9864
9917
  up.link = (function () {
9865
9918
  const u = up.util;
9866
9919
  const e = up.element;
9867
- const linkPreloader = new up.LinkPreloader();
9868
9920
  let lastMousedownTarget = null;
9869
9921
  const LINKS_WITH_LOCAL_HTML = ['a[up-content]', 'a[up-fragment]', 'a[up-document]'];
9870
9922
  const LINKS_WITH_REMOTE_HTML = ['a[href]', '[up-href]'];
@@ -9898,10 +9950,9 @@ up.link = (function () {
9898
9950
  }
9899
9951
  function reset() {
9900
9952
  lastMousedownTarget = null;
9901
- linkPreloader.reset();
9902
9953
  }
9903
- const follow = up.mockable(function (link, options) {
9904
- return up.render(followOptions(link, options));
9954
+ const follow = up.mockable(function (link, options, parserOptions) {
9955
+ return up.render(followOptions(link, options, parserOptions));
9905
9956
  });
9906
9957
  function parseRequestOptions(link, options, parserOptions) {
9907
9958
  options = u.options(options);
@@ -9923,6 +9974,7 @@ up.link = (function () {
9923
9974
  return options;
9924
9975
  }
9925
9976
  function followOptions(link, options, parserOptions) {
9977
+ var _a;
9926
9978
  link = up.fragment.get(link);
9927
9979
  options = u.options(options);
9928
9980
  const parser = new up.OptionsParser(link, options, Object.assign({ fail: true }, parserOptions));
@@ -9976,10 +10028,9 @@ up.link = (function () {
9976
10028
  parser.booleanOrString('location');
9977
10029
  parser.booleanOrString('title');
9978
10030
  parser.boolean('metaTags');
10031
+ parser.booleanOrString('lang');
9979
10032
  parser.include(up.motion.motionOptions);
9980
- if (!options.guardEvent) {
9981
- options.guardEvent = up.event.build('up:link:follow', { log: 'Following link' });
9982
- }
10033
+ (_a = options.guardEvent) !== null && _a !== void 0 ? _a : (options.guardEvent = up.event.build('up:link:follow', { log: ['Following link %o', link] }));
9983
10034
  return options;
9984
10035
  }
9985
10036
  function preload(link, options) {
@@ -10018,9 +10069,10 @@ up.link = (function () {
10018
10069
  if (link.matches('a[href], button')) {
10019
10070
  return;
10020
10071
  }
10072
+ let role = link.matches('a') ? 'link' : 'button';
10021
10073
  e.setMissingAttrs(link, {
10022
10074
  tabindex: '0',
10023
- role: 'link',
10075
+ role,
10024
10076
  'up-clickable': ''
10025
10077
  });
10026
10078
  link.addEventListener('keydown', function (event) {
@@ -10080,6 +10132,38 @@ up.link = (function () {
10080
10132
  const method = followMethod(link);
10081
10133
  return up.network.isSafeMethod(method);
10082
10134
  }
10135
+ function onLoadCondition(condition, link, callback) {
10136
+ switch (condition) {
10137
+ case 'insert':
10138
+ callback();
10139
+ break;
10140
+ case 'reveal': {
10141
+ let margin = e.numberAttr(link, 'up-intersect-margin');
10142
+ up.fragment.onFirstIntersect(link, callback, { margin });
10143
+ break;
10144
+ }
10145
+ case 'hover':
10146
+ new up.LinkFollowIntent(link, callback);
10147
+ break;
10148
+ case 'manual':
10149
+ break;
10150
+ }
10151
+ }
10152
+ function loadDeferred(link, options) {
10153
+ let guardEvent = up.event.build('up:deferred:load', { log: ['Loading deferred %o', link] });
10154
+ let forcedOptions = Object.assign({ navigate: false, guardEvent }, options);
10155
+ let defaults = {
10156
+ target: ':origin',
10157
+ cache: 'auto',
10158
+ revalidate: 'auto',
10159
+ feedback: true,
10160
+ };
10161
+ return follow(link, forcedOptions, { defaults });
10162
+ }
10163
+ up.attribute('up-defer', { defaultValue: 'insert' }, function (link, condition) {
10164
+ let doLoad = () => up.error.muteUncriticalRejection(loadDeferred(link));
10165
+ onLoadCondition(condition, link, doLoad);
10166
+ });
10083
10167
  up.on('up:click', config.selectorFn('followSelectors'), function (event, link) {
10084
10168
  if (shouldFollowEvent(event, link)) {
10085
10169
  up.event.halt(event, { log: true });
@@ -10087,21 +10171,20 @@ up.link = (function () {
10087
10171
  up.error.muteUncriticalRejection(follow(link));
10088
10172
  }
10089
10173
  });
10090
- up.macro('[up-expand]', function (area) {
10091
- const selector = area.getAttribute('up-expand') || 'a, [up-href]';
10092
- let childLink = e.get(area, selector);
10174
+ up.attribute('up-expand', { defaultValue: 'a, [up-href]', macro: true }, function (area, childLinkSelector) {
10175
+ let childLink = e.get(area, childLinkSelector);
10093
10176
  if (childLink) {
10094
- const areaAttrs = e.upAttrs(childLink);
10095
- areaAttrs['up-href'] || (areaAttrs['up-href'] = childLink.getAttribute('href'));
10096
- e.setMissingAttrs(area, areaAttrs);
10097
- const areaClasses = e.upClasses(childLink);
10098
- area.classList.add(...areaClasses);
10177
+ e.setMissingAttrs(area, Object.assign({ 'up-href': e.attr(childLink, 'href') }, e.upAttrs(childLink)));
10178
+ area.classList.add(...e.upClasses(childLink));
10099
10179
  makeFollowable(area);
10100
10180
  }
10101
10181
  });
10102
10182
  up.compiler(config.selectorFn('preloadSelectors'), function (link) {
10183
+ var _a;
10103
10184
  if (!isPreloadDisabled(link)) {
10104
- linkPreloader.watchLink(link);
10185
+ let doPreload = () => up.error.muteUncriticalRejection(preload(link));
10186
+ let condition = (_a = e.booleanOrStringAttr(link, 'up-preload', null)) !== null && _a !== void 0 ? _a : 'hover';
10187
+ onLoadCondition(condition, link, doPreload);
10105
10188
  }
10106
10189
  });
10107
10190
  up.on('up:framework:reset', reset);
@@ -10110,18 +10193,17 @@ up.link = (function () {
10110
10193
  followOptions,
10111
10194
  preload,
10112
10195
  makeFollowable,
10113
- makeClickable,
10114
10196
  isSafe,
10115
10197
  isFollowable,
10116
10198
  shouldFollowEvent,
10117
- followMethod,
10118
10199
  convertClicks,
10119
10200
  config,
10120
10201
  combineFollowableSelectors,
10121
- preloadIssue,
10202
+ loadDeferred,
10122
10203
  };
10123
10204
  })();
10124
10205
  up.follow = up.link.follow;
10206
+ up.deferred = { load: up.link.loadDeferred };
10125
10207
 
10126
10208
 
10127
10209
  /***/ }),
@@ -10194,7 +10276,8 @@ up.form = (function () {
10194
10276
  options.guardEvent || (options.guardEvent = up.event.build('up:form:submit', {
10195
10277
  submitButton: options.submitButton,
10196
10278
  log: 'Submitting form',
10197
- params: options.params
10279
+ params: options.params,
10280
+ form,
10198
10281
  }));
10199
10282
  options.origin || (options.origin = up.viewport.focusedElementWithin(form) || options.submitButton || form);
10200
10283
  parser.include(up.link.followOptions);
@@ -10469,7 +10552,9 @@ up.form = (function () {
10469
10552
  validator.watchContainer(fieldOrForm);
10470
10553
  });
10471
10554
  function validatingFieldSelector() {
10472
- return config.fieldSelectors.map((selector) => `${selector}[up-validate], [up-validate] ${selector}`).join(', ');
10555
+ let includes = config.fieldSelectors.map((selector) => `${selector}[up-validate], [up-validate] ${selector}`);
10556
+ let excludes = ['[up-validate=false]'];
10557
+ return e.unionSelector(includes, excludes);
10473
10558
  }
10474
10559
  up.compiler('[up-switch]', (switcher) => {
10475
10560
  switchTargets(switcher);
@@ -10480,8 +10565,8 @@ up.form = (function () {
10480
10565
  up.compiler('[up-show-for]:not(.up-switched), [up-hide-for]:not(.up-switched)', (element) => {
10481
10566
  switchTarget(element);
10482
10567
  });
10483
- up.compiler('[up-watch]', (formOrField) => watch(formOrField));
10484
- up.compiler('[up-autosubmit]', (formOrField) => autosubmit(formOrField));
10568
+ up.attribute('up-watch', (formOrField) => watch(formOrField));
10569
+ up.attribute('up-autosubmit', (formOrField) => autosubmit(formOrField));
10485
10570
  return {
10486
10571
  config,
10487
10572
  submit,
@@ -10523,6 +10608,7 @@ up.feedback = (function () {
10523
10608
  const config = new up.Config(() => ({
10524
10609
  currentClasses: ['up-current'],
10525
10610
  navSelectors: ['[up-nav]', 'nav'],
10611
+ noNavSelectors: ['[up-nav=false]'],
10526
10612
  }));
10527
10613
  function reset() {
10528
10614
  up.layer.root.feedbackLocation = null;
@@ -10530,9 +10616,6 @@ up.feedback = (function () {
10530
10616
  const CLASS_ACTIVE = 'up-active';
10531
10617
  const CLASS_LOADING = 'up-loading';
10532
10618
  const SELECTOR_LINK = 'a, [up-href]';
10533
- function navSelector() {
10534
- return config.selector('navSelectors');
10535
- }
10536
10619
  function normalizeURL(url) {
10537
10620
  if (url) {
10538
10621
  return u.normalizeURL(url, { trailingSlash: false, hash: false });
@@ -10541,40 +10624,23 @@ up.feedback = (function () {
10541
10624
  function linkURLs(link) {
10542
10625
  return link.upFeedbackURLs || (link.upFeedbackURLs = new up.LinkFeedbackURLs(link));
10543
10626
  }
10544
- function updateFragment(fragment) {
10545
- const layerOption = { layer: up.layer.get(fragment) };
10546
- if (up.fragment.closest(fragment, navSelector(), layerOption)) {
10547
- const links = up.fragment.subtree(fragment, SELECTOR_LINK, layerOption);
10548
- updateLinks(links, layerOption);
10549
- }
10550
- else {
10551
- updateLinksWithinNavs(fragment, layerOption);
10627
+ function updateFragment(fragment, { layer } = {}) {
10628
+ layer || (layer = up.layer.get(fragment));
10629
+ let layerLocation = getNormalizedLayerLocation(layer);
10630
+ const navSelector = config.selector('navSelectors');
10631
+ const navLinkSelector = `${navSelector} :is(${SELECTOR_LINK}), ${navSelector}:is(${SELECTOR_LINK})`;
10632
+ const links = up.fragment.all(navLinkSelector, { layer });
10633
+ for (let link of links) {
10634
+ const isCurrent = linkURLs(link).isCurrent(layerLocation);
10635
+ for (let currentClass of config.currentClasses) {
10636
+ link.classList.toggle(currentClass, isCurrent);
10637
+ }
10638
+ e.toggleAttr(link, 'aria-current', 'page', isCurrent);
10552
10639
  }
10553
10640
  }
10554
- function updateLinksWithinNavs(fragment, options) {
10555
- const navs = up.fragment.subtree(fragment, navSelector(), options);
10556
- const links = u.flatMap(navs, nav => e.subtree(nav, SELECTOR_LINK));
10557
- updateLinks(links, options);
10558
- }
10559
10641
  function getNormalizedLayerLocation(layer) {
10560
10642
  return layer.feedbackLocation || normalizeURL(layer.location);
10561
10643
  }
10562
- function updateLinks(links, options = {}) {
10563
- if (!links.length) {
10564
- return;
10565
- }
10566
- const layer = options.layer || up.layer.get(links[0]);
10567
- let layerLocation = getNormalizedLayerLocation(layer);
10568
- if (layerLocation) {
10569
- for (let link of links) {
10570
- const isCurrent = linkURLs(link).isCurrent(layerLocation);
10571
- for (let currentClass of config.currentClasses) {
10572
- link.classList.toggle(currentClass, isCurrent);
10573
- }
10574
- e.toggleAttr(link, 'aria-current', 'page', isCurrent);
10575
- }
10576
- }
10577
- }
10578
10644
  function findActivatableArea(element) {
10579
10645
  return e.ancestor(element, SELECTOR_LINK) || element;
10580
10646
  }
@@ -10602,7 +10668,7 @@ up.feedback = (function () {
10602
10668
  const layerLocation = getNormalizedLayerLocation(layer.location);
10603
10669
  if (!processedLocation || (processedLocation !== layerLocation)) {
10604
10670
  layer.feedbackLocation = layerLocation;
10605
- updateLinksWithinNavs(layer.element, { layer });
10671
+ updateFragment(layer.element, { layer });
10606
10672
  }
10607
10673
  }
10608
10674
  function onBrowserLocationChanged() {
@@ -10637,6 +10703,7 @@ up.radio = (function () {
10637
10703
  const e = up.element;
10638
10704
  const config = new up.Config(() => ({
10639
10705
  hungrySelectors: ['[up-hungry]'],
10706
+ noHungrySelectors: ['[up-hungry=false]'],
10640
10707
  pollInterval: 30000,
10641
10708
  }));
10642
10709
  function hungrySteps(renderOptions) {
@@ -10682,7 +10749,7 @@ up.radio = (function () {
10682
10749
  parser.string('ifLayer', { default: 'front' });
10683
10750
  return options;
10684
10751
  }
10685
- up.compiler('[up-poll]:not([up-poll=false])', function (fragment) {
10752
+ up.attribute('up-poll', function (fragment) {
10686
10753
  up.FragmentPolling.forFragment(fragment).onPollAttributeObserved();
10687
10754
  });
10688
10755
  up.macro('[up-flashes]', function (fragment) {