unpoly-rails 3.7.3.2 → 3.8.0

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'
9
9
  };
10
10
 
11
11
 
@@ -229,11 +229,6 @@ up.util = (function () {
229
229
  function isArguments(value) {
230
230
  return Object.prototype.toString.call(value) === '[object Arguments]';
231
231
  }
232
- function nullToUndefined(value) {
233
- if (!isNull(value)) {
234
- return value;
235
- }
236
- }
237
232
  function wrapList(value) {
238
233
  if (isList(value)) {
239
234
  return value;
@@ -337,9 +332,6 @@ up.util = (function () {
337
332
  function compact(array) {
338
333
  return filterList(array, isGiven);
339
334
  }
340
- function filterMap(list, mapping) {
341
- return filterList(map(list, mapping), isDefined);
342
- }
343
335
  function compactObject(object) {
344
336
  return pickBy(object, isGiven);
345
337
  }
@@ -389,9 +381,6 @@ up.util = (function () {
389
381
  function queueTask(task) {
390
382
  return setTimeout(task);
391
383
  }
392
- function queueMicrotask(task) {
393
- return Promise.resolve().then(task);
394
- }
395
384
  function last(value) {
396
385
  return value[value.length - 1];
397
386
  }
@@ -399,6 +388,9 @@ up.util = (function () {
399
388
  let indexOf = value.indexOf || Array.prototype.indexOf;
400
389
  return indexOf.call(value, subValue) >= 0;
401
390
  }
391
+ function containsAll(values, subValues) {
392
+ return every(subValues, (subValue) => contains(values, subValue));
393
+ }
402
394
  function objectContains(object, subObject) {
403
395
  const reducedValue = pick(object, Object.keys(subObject));
404
396
  return isEqual(subObject, reducedValue);
@@ -582,6 +574,14 @@ up.util = (function () {
582
574
  function reverse(list) {
583
575
  return copy(list).reverse();
584
576
  }
577
+ function replaceValue(value, matchValue, replacementValue) {
578
+ if (value === matchValue) {
579
+ return replacementValue;
580
+ }
581
+ else {
582
+ return value;
583
+ }
584
+ }
585
585
  function renameKeys(object, renameKeyFn) {
586
586
  const renamed = {};
587
587
  for (let key in object) {
@@ -732,7 +732,6 @@ up.util = (function () {
732
732
  normalizeMethod,
733
733
  methodAllowsPayload,
734
734
  copy,
735
- copyArrayLike,
736
735
  merge,
737
736
  mergeDefined,
738
737
  options: newOptions,
@@ -746,7 +745,6 @@ up.util = (function () {
746
745
  every,
747
746
  find: findInList,
748
747
  filter: filterList,
749
- filterMap: filterMap,
750
748
  reject,
751
749
  intersect,
752
750
  compact,
@@ -778,6 +776,7 @@ up.util = (function () {
778
776
  isRegExp,
779
777
  timer: scheduleTimer,
780
778
  contains,
779
+ containsAll,
781
780
  objectContains,
782
781
  toArray,
783
782
  pick,
@@ -804,7 +803,6 @@ up.util = (function () {
804
803
  isBasicObjectProperty,
805
804
  isCrossOrigin,
806
805
  task: queueTask,
807
- microtask: queueMicrotask,
808
806
  isEqual,
809
807
  parseTokens,
810
808
  wrapList,
@@ -815,10 +813,9 @@ up.util = (function () {
815
813
  delegate: defineDelegates,
816
814
  reverse,
817
815
  camelToKebabCase,
818
- nullToUndefined,
816
+ replaceValue,
819
817
  sprintf,
820
818
  renameKeys,
821
- negate,
822
819
  memoizeMethod,
823
820
  safeStringifyJSON,
824
821
  variant,
@@ -885,7 +882,9 @@ up.fail = up.error.fail;
885
882
  /* 5 */
886
883
  /***/ (() => {
887
884
 
888
- up.migrate = { config: {} };
885
+ up.migrate = {
886
+ config: {},
887
+ };
889
888
 
890
889
 
891
890
  /***/ }),
@@ -1179,7 +1178,7 @@ up.element = (function () {
1179
1178
  }
1180
1179
  }
1181
1180
  function idSelector(id) {
1182
- if (id.match(/^[a-z0-9\-_]+$/i)) {
1181
+ if (id.match(/^[a-z][a-z0-9\-_]*$/i)) {
1183
1182
  return `#${id}`;
1184
1183
  }
1185
1184
  else {
@@ -1218,16 +1217,9 @@ up.element = (function () {
1218
1217
  paint(element);
1219
1218
  return undo;
1220
1219
  }
1221
- function hasCSSTransition(elementOrStyleHash) {
1222
- let styleHash;
1223
- if (u.isOptions(elementOrStyleHash)) {
1224
- styleHash = elementOrStyleHash;
1225
- }
1226
- else {
1227
- styleHash = computedStyle(elementOrStyleHash);
1228
- }
1229
- const prop = styleHash.transitionProperty;
1230
- const duration = styleHash.transitionDuration;
1220
+ function hasCSSTransition(styleHash) {
1221
+ const prop = styleHash['transition-property'];
1222
+ const duration = styleHash['transition-duration'];
1231
1223
  const noTransition = ((prop === 'none') || ((prop === 'all') && (duration === 0)));
1232
1224
  return !noTransition;
1233
1225
  }
@@ -1236,8 +1228,8 @@ up.element = (function () {
1236
1228
  element.style.position = 'absolute';
1237
1229
  const offsetParentRect = element.offsetParent.getBoundingClientRect();
1238
1230
  setInlineStyle(element, {
1239
- left: elementRectAsFixed.left - computedStyleNumber(element, 'margin-left') - offsetParentRect.left,
1240
- top: elementRectAsFixed.top - computedStyleNumber(element, 'margin-top') - offsetParentRect.top,
1231
+ left: (elementRectAsFixed.left - computedStyleNumber(element, 'margin-left') - offsetParentRect.left) + 'px',
1232
+ top: (elementRectAsFixed.top - computedStyleNumber(element, 'margin-top') - offsetParentRect.top) + 'px',
1241
1233
  right: '',
1242
1234
  bottom: ''
1243
1235
  });
@@ -1269,9 +1261,6 @@ up.element = (function () {
1269
1261
  element.appendChild(wrapper);
1270
1262
  return wrapper;
1271
1263
  }
1272
- function isWrapper(element) {
1273
- return element.matches('up-wrapper');
1274
- }
1275
1264
  function preservingFocus(fn) {
1276
1265
  const oldFocusElement = document.activeElement;
1277
1266
  try {
@@ -1284,7 +1273,8 @@ up.element = (function () {
1284
1273
  }
1285
1274
  }
1286
1275
  function stringAttr(element, attribute) {
1287
- return u.nullToUndefined(element.getAttribute(attribute));
1276
+ let value = element.getAttribute(attribute);
1277
+ return u.replaceValue(value, null, undefined);
1288
1278
  }
1289
1279
  function booleanAttr(element, attribute, pass) {
1290
1280
  if (!element.hasAttribute(attribute))
@@ -1309,14 +1299,15 @@ up.element = (function () {
1309
1299
  }
1310
1300
  }
1311
1301
  }
1312
- function booleanOrStringAttr(element, attribute) {
1313
- return booleanAttr(element, attribute, true);
1302
+ function booleanOrStringAttr(element, attribute, trueValue = true) {
1303
+ let value = booleanAttr(element, attribute, true);
1304
+ return value === true ? trueValue : value;
1314
1305
  }
1315
1306
  function numberAttr(element, attribute) {
1316
1307
  let value = element.getAttribute(attribute);
1317
1308
  if (value) {
1318
1309
  value = value.replace(/_/g, '');
1319
- if (value.match(/^[\d.]+$/)) {
1310
+ if (value.match(/^-?[\d.]+$/)) {
1320
1311
  return parseFloat(value);
1321
1312
  }
1322
1313
  }
@@ -1352,17 +1343,13 @@ up.element = (function () {
1352
1343
  element.classList.add(klass);
1353
1344
  return () => element.classList.remove(klass);
1354
1345
  }
1355
- function setTemporaryAttr(element, attr, value) {
1356
- element.setAttribute(attr, value);
1357
- return () => element.removeAttribute(element, attr);
1358
- }
1359
1346
  function computedStyle(element, props) {
1360
1347
  const style = window.getComputedStyle(element);
1361
1348
  return extractFromStyleObject(style, props);
1362
1349
  }
1363
1350
  function computedStyleNumber(element, prop) {
1364
1351
  const rawValue = computedStyle(element, prop);
1365
- if (u.isGiven(rawValue)) {
1352
+ if (u.isPresent(rawValue)) {
1366
1353
  return parseFloat(rawValue);
1367
1354
  }
1368
1355
  }
@@ -1371,14 +1358,18 @@ up.element = (function () {
1371
1358
  return extractFromStyleObject(style, props);
1372
1359
  }
1373
1360
  function extractFromStyleObject(style, keyOrKeys) {
1361
+ if (up.migrate.loaded)
1362
+ keyOrKeys = up.migrate.fixStyleProps(keyOrKeys);
1374
1363
  if (u.isString(keyOrKeys)) {
1375
- return style[keyOrKeys];
1364
+ return style.getPropertyValue(keyOrKeys);
1376
1365
  }
1377
1366
  else {
1378
- return u.pick(style, keyOrKeys);
1367
+ return u.mapObject(keyOrKeys, (key) => [key, style.getPropertyValue(key)]);
1379
1368
  }
1380
1369
  }
1381
- function setInlineStyle(element, props) {
1370
+ function setInlineStyle(element, props, unit = '') {
1371
+ if (up.migrate.loaded)
1372
+ props = up.migrate.fixStyleProps(props, unit);
1382
1373
  if (u.isString(props)) {
1383
1374
  element.setAttribute('style', props);
1384
1375
  }
@@ -1386,37 +1377,10 @@ up.element = (function () {
1386
1377
  const { style } = element;
1387
1378
  for (let key in props) {
1388
1379
  let value = props[key];
1389
- value = normalizeStyleValueForWrite(key, value);
1390
- style[key] = value;
1380
+ style.setProperty(key, value + unit);
1391
1381
  }
1392
1382
  }
1393
1383
  }
1394
- function normalizeStyleValueForWrite(key, value) {
1395
- if (u.isMissing(value)) {
1396
- value = '';
1397
- }
1398
- else if (CSS_LENGTH_PROPS.has(key.toLowerCase().replace(/-/, ''))) {
1399
- value = cssLength(value);
1400
- }
1401
- return value;
1402
- }
1403
- const CSS_LENGTH_PROPS = new Set([
1404
- 'top', 'right', 'bottom', 'left',
1405
- 'padding', 'paddingtop', 'paddingright', 'paddingbottom', 'paddingleft',
1406
- 'margin', 'margintop', 'marginright', 'marginbottom', 'marginleft',
1407
- 'borderwidth', 'bordertopwidth', 'borderrightwidth', 'borderbottomwidth', 'borderleftwidth',
1408
- 'width', 'height',
1409
- 'maxwidth', 'maxheight',
1410
- 'minwidth', 'minheight',
1411
- ]);
1412
- function cssLength(obj) {
1413
- if (u.isNumber(obj) || (u.isString(obj) && /^\d+$/.test(obj))) {
1414
- return obj.toString() + "px";
1415
- }
1416
- else {
1417
- return obj;
1418
- }
1419
- }
1420
1384
  function isVisible(element) {
1421
1385
  return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
1422
1386
  }
@@ -1441,6 +1405,18 @@ up.element = (function () {
1441
1405
  function crossOriginSelector(attr) {
1442
1406
  return `[${attr}*="//"]:not([${attr}*="//${location.host}/"])`;
1443
1407
  }
1408
+ function isIntersectingWindow(element, { margin = 0 } = {}) {
1409
+ const rect = up.Rect.fromElement(element);
1410
+ rect.grow(margin);
1411
+ return (rect.bottom > 0) && (rect.top < window.innerHeight) &&
1412
+ (rect.right > 0) && (rect.left < window.innerWidth);
1413
+ }
1414
+ function unionSelector(includes, excludes) {
1415
+ let selector = `:is(${includes.join()})`;
1416
+ if (u.isPresent(excludes))
1417
+ selector += `:not(${excludes.join()})`;
1418
+ return selector;
1419
+ }
1444
1420
  return {
1445
1421
  subtree,
1446
1422
  contains,
@@ -1475,7 +1451,6 @@ up.element = (function () {
1475
1451
  setMissingAttr,
1476
1452
  unwrap,
1477
1453
  wrapChildren,
1478
- isWrapper,
1479
1454
  attr: stringAttr,
1480
1455
  booleanAttr,
1481
1456
  numberAttr,
@@ -1492,11 +1467,12 @@ up.element = (function () {
1492
1467
  upClasses,
1493
1468
  toggleAttr,
1494
1469
  addTemporaryClass,
1495
- setTemporaryAttr,
1496
1470
  cleanJQuery,
1497
1471
  parseSelector,
1498
1472
  isEmpty,
1499
1473
  crossOriginSelector,
1474
+ isIntersectingWindow,
1475
+ unionSelector,
1500
1476
  };
1501
1477
  })();
1502
1478
 
@@ -1609,6 +1585,7 @@ up.Record = class Record {
1609
1585
  /***/ (() => {
1610
1586
 
1611
1587
  const u = up.util;
1588
+ const e = up.element;
1612
1589
  up.Config = class Config {
1613
1590
  constructor(blueprintFn = (() => ({}))) {
1614
1591
  this._blueprintFn = blueprintFn;
@@ -1624,10 +1601,7 @@ up.Config = class Config {
1624
1601
  selector(prop) {
1625
1602
  let includes = this[prop];
1626
1603
  let excludes = this['no' + u.upperCaseFirst(prop)];
1627
- let selector = `:is(${includes.join()})`;
1628
- if (u.isPresent(excludes))
1629
- selector += `:not(${excludes.join()})`;
1630
- return selector;
1604
+ return e.unionSelector(includes, excludes);
1631
1605
  }
1632
1606
  selectorFn(prop) {
1633
1607
  return () => this.selector(prop);
@@ -1797,6 +1771,12 @@ up.Rect = class Rect extends up.Record {
1797
1771
  get right() {
1798
1772
  return this.left + this.width;
1799
1773
  }
1774
+ grow(padding) {
1775
+ this.left -= padding;
1776
+ this.top -= padding;
1777
+ this.width += padding * 2;
1778
+ this.height += padding * 2;
1779
+ }
1800
1780
  static fromElement(element) {
1801
1781
  return new (this)(element.getBoundingClientRect());
1802
1782
  }
@@ -1808,64 +1788,49 @@ up.Rect = class Rect extends up.Record {
1808
1788
  /***/ (() => {
1809
1789
 
1810
1790
  const e = up.element;
1791
+ const SHIFT_CLASS = 'up-scrollbar-away';
1811
1792
  up.BodyShifter = class BodyShifter {
1812
1793
  constructor() {
1813
- this._unshiftFns = [];
1814
1794
  this._anchoredElements = new Set();
1815
1795
  this._stack = 0;
1796
+ this._cleaners = [];
1816
1797
  }
1817
1798
  lowerStack() {
1818
- this._stack--;
1819
- if (this._stack === 0) {
1799
+ if (--this._stack === 0)
1820
1800
  this._unshiftNow();
1821
- }
1822
1801
  }
1823
1802
  raiseStack() {
1824
- this._stack++;
1825
- if (this._stack === 1) {
1803
+ if (++this._stack === 1)
1826
1804
  this._shiftNow();
1827
- }
1828
1805
  }
1829
1806
  onAnchoredElementInserted(element) {
1830
1807
  this._anchoredElements.add(element);
1831
- if (this._isShifted()) {
1832
- this._shiftAnchoredElement(element);
1833
- }
1808
+ this._shiftElement(element, 'right');
1834
1809
  return () => this._anchoredElements.delete(element);
1835
1810
  }
1836
1811
  _isShifted() {
1837
- return this._scrollbarTookSpace && this._stack > 0;
1812
+ return this._rootScrollbarWidth && this._stack > 0;
1838
1813
  }
1839
1814
  _shiftNow() {
1840
- this._scrollbarWidth = up.viewport.scrollbarWidth();
1841
- this._scrollbarTookSpace = up.viewport.rootHasReducedWidthFromScrollbar();
1842
- if (!this._scrollbarTookSpace)
1843
- return;
1844
- this._shiftBody();
1815
+ this._rootScrollbarWidth = up.viewport.rootScrollbarWidth();
1816
+ this._cleaners.push(e.setTemporaryStyle(e.root, {
1817
+ '--up-scrollbar-width': this._rootScrollbarWidth + 'px'
1818
+ }));
1819
+ this._shiftElement(document.body, 'padding-right');
1845
1820
  for (let element of this._anchoredElements) {
1846
- this._shiftAnchoredElement(element);
1821
+ this._shiftElement(element, 'right');
1847
1822
  }
1848
1823
  }
1849
- _shiftBody() {
1850
- const overflowElement = up.viewport.rootOverflowElement();
1851
- this._changeStyle(overflowElement, { overflowY: 'hidden' });
1852
- const { body } = document;
1853
- const bodyRightPadding = e.styleNumber(body, 'paddingRight');
1854
- const bodyRightShift = this._scrollbarWidth + bodyRightPadding;
1855
- this._changeStyle(body, { paddingRight: bodyRightShift });
1856
- }
1857
- _shiftAnchoredElement(element) {
1858
- const elementRight = e.styleNumber(element, 'right');
1859
- const elementRightShift = this._scrollbarWidth + elementRight;
1860
- this._changeStyle(element, { right: elementRightShift });
1861
- }
1862
- _changeStyle(element, styles) {
1863
- this._unshiftFns.push(e.setTemporaryStyle(element, styles));
1824
+ _shiftElement(element, styleProp) {
1825
+ if (!this._isShifted())
1826
+ return;
1827
+ let originalValue = e.style(element, styleProp);
1828
+ this._cleaners.push(e.setTemporaryStyle(e.root, { ['--up-original-' + styleProp]: originalValue }), e.addTemporaryClass(element, SHIFT_CLASS));
1864
1829
  }
1865
1830
  _unshiftNow() {
1866
- let unshiftFn;
1867
- while (unshiftFn = this._unshiftFns.pop()) {
1868
- unshiftFn();
1831
+ let cleaner;
1832
+ while (cleaner = this._cleaners.pop()) {
1833
+ cleaner();
1869
1834
  }
1870
1835
  }
1871
1836
  };
@@ -3058,6 +3023,7 @@ up.Change.FromContent = (_a = class FromContent extends up.Change {
3058
3023
  }
3059
3024
  this.options.title = this.improveHistoryValue(this.options.title, responseDoc.title);
3060
3025
  this.options.metaTags = this.improveHistoryValue(this.options.metaTags, responseDoc.metaTags);
3026
+ this.options.lang = this.improveHistoryValue(this.options.lang, responseDoc.lang);
3061
3027
  }
3062
3028
  _defaultPlacement() {
3063
3029
  if (!this.options.document && !this.options.fragment) {
@@ -3229,20 +3195,17 @@ up.CompilerPass = class CompilerPass {
3229
3195
  const u = up.util;
3230
3196
  const e = up.element;
3231
3197
  up.CSSTransition = class CSSTransition {
3232
- constructor(element, lastFrameKebab, options) {
3198
+ constructor(element, lastFrame, options) {
3233
3199
  this._element = element;
3234
- this._lastFrameKebab = lastFrameKebab;
3235
- this._lastFrameKeysKebab = Object.keys(this._lastFrameKebab);
3236
- if (u.some(this._lastFrameKeysKebab, key => key.match(/A-Z/))) {
3237
- up.fail('Animation keys must be kebab-case');
3238
- }
3200
+ this._lastFrame = lastFrame;
3201
+ this._lastFrameKeys = Object.keys(this._lastFrame);
3239
3202
  this._finishEvent = options.finishEvent;
3240
3203
  this._duration = options.duration;
3241
3204
  this._easing = options.easing;
3242
3205
  this._finished = false;
3243
3206
  }
3244
3207
  start() {
3245
- if (this._lastFrameKeysKebab.length === 0) {
3208
+ if (this._lastFrameKeys.length === 0) {
3246
3209
  this._finished = true;
3247
3210
  return Promise.resolve();
3248
3211
  }
@@ -3266,9 +3229,7 @@ up.CSSTransition = class CSSTransition {
3266
3229
  }
3267
3230
  _startFallbackTimer() {
3268
3231
  const timingTolerance = 100;
3269
- this._fallbackTimer = u.timer((this._duration + timingTolerance), () => {
3270
- this._finish();
3271
- });
3232
+ this._fallbackTimer = u.timer((this._duration + timingTolerance), () => this._finish());
3272
3233
  }
3273
3234
  _stopFallbackTimer() {
3274
3235
  clearTimeout(this._fallbackTimer);
@@ -3284,11 +3245,10 @@ up.CSSTransition = class CSSTransition {
3284
3245
  if (elapsed <= (0.25 * this._duration)) {
3285
3246
  return;
3286
3247
  }
3287
- const completedPropertyKebab = event.propertyName;
3288
- if (!u.contains(this._lastFrameKeysKebab, completedPropertyKebab)) {
3289
- return;
3248
+ const completedProperty = event.propertyName;
3249
+ if (u.contains(this._lastFrameKeys, completedProperty)) {
3250
+ this._finish();
3290
3251
  }
3291
- this._finish();
3292
3252
  }
3293
3253
  _finish() {
3294
3254
  if (this._finished) {
@@ -3304,16 +3264,16 @@ up.CSSTransition = class CSSTransition {
3304
3264
  }
3305
3265
  _pauseOldTransition() {
3306
3266
  const oldTransition = e.style(this._element, [
3307
- 'transitionProperty',
3308
- 'transitionDuration',
3309
- 'transitionDelay',
3310
- 'transitionTimingFunction'
3267
+ 'transition-property',
3268
+ 'transition-duration',
3269
+ 'transition-delay',
3270
+ 'transition-timing-function'
3311
3271
  ]);
3312
3272
  if (e.hasCSSTransition(oldTransition)) {
3313
- if (oldTransition.transitionProperty !== 'all') {
3314
- const oldTransitionProperties = oldTransition.transitionProperty.split(/\s*,\s*/);
3315
- const oldTransitionFrameKebab = e.style(this._element, oldTransitionProperties);
3316
- this._setOldTransitionTargetFrame = e.setTemporaryStyle(this._element, oldTransitionFrameKebab);
3273
+ if (oldTransition['transition-property'] !== 'all') {
3274
+ const oldTransitionProperties = oldTransition['transition-property'].split(/\s*,\s*/);
3275
+ const oldTransitionFrame = e.style(this._element, oldTransitionProperties);
3276
+ this._setOldTransitionTargetFrame = e.setTemporaryStyle(this._element, oldTransitionFrame);
3317
3277
  }
3318
3278
  this._setOldTransition = e.concludeCSSTransition(this._element);
3319
3279
  }
@@ -3324,11 +3284,11 @@ up.CSSTransition = class CSSTransition {
3324
3284
  }
3325
3285
  _startMotion() {
3326
3286
  e.setStyle(this._element, {
3327
- transitionProperty: Object.keys(this._lastFrameKebab).join(', '),
3328
- transitionDuration: `${this._duration}ms`,
3329
- transitionTimingFunction: this._easing
3287
+ 'transition-property': this._lastFrameKeys.join(),
3288
+ 'transition-duration': `${this._duration}ms`,
3289
+ 'transition-timing-function': this._easing
3330
3290
  });
3331
- e.setStyle(this._element, this._lastFrameKebab);
3291
+ e.setStyle(this._element, this._lastFrame);
3332
3292
  }
3333
3293
  };
3334
3294
 
@@ -3773,6 +3733,7 @@ up.FieldWatcher = class FieldWatcher {
3773
3733
  /***/ (() => {
3774
3734
 
3775
3735
  const u = up.util;
3736
+ const e = up.element;
3776
3737
  up.FormValidator = class FormValidator {
3777
3738
  constructor(form) {
3778
3739
  this._form = form;
@@ -3832,7 +3793,7 @@ up.FormValidator = class FormValidator {
3832
3793
  }
3833
3794
  }
3834
3795
  _getTargetSelectorSolutions({ target, origin }) {
3835
- if (u.isString(target) && target) {
3796
+ if (u.isString(target)) {
3836
3797
  up.puts('up.validate()', 'Validating target "%s"', target);
3837
3798
  let simpleSelectors = up.fragment.splitTarget(target);
3838
3799
  return u.compact(simpleSelectors.map(function (simpleSelector) {
@@ -3861,7 +3822,7 @@ up.FormValidator = class FormValidator {
3861
3822
  _getValidateAttrSolutions(field) {
3862
3823
  let containerWithAttr = field.closest('[up-validate]');
3863
3824
  if (containerWithAttr) {
3864
- let target = containerWithAttr.getAttribute('up-validate');
3825
+ let target = e.booleanOrStringAttr(containerWithAttr, 'up-validate');
3865
3826
  return this._getTargetSelectorSolutions({ target, origin: field });
3866
3827
  }
3867
3828
  }
@@ -3907,7 +3868,8 @@ up.FormValidator = class FormValidator {
3907
3868
  options.guardEvent = up.event.build('up:form:validate', {
3908
3869
  fields: dirtyFields,
3909
3870
  log: 'Validating form',
3910
- params: options.params
3871
+ params: options.params,
3872
+ form: this._form,
3911
3873
  });
3912
3874
  this._rendering = true;
3913
3875
  let renderingPromise = this._nextRenderPromise;
@@ -4548,6 +4510,7 @@ up.Layer = class Layer extends up.Record {
4548
4510
  this.savedTitle = document.title;
4549
4511
  this.savedMetaTags = up.history.findMetaTags();
4550
4512
  this.savedLocation = up.history.location;
4513
+ this.savedLang = up.history.getLang();
4551
4514
  }
4552
4515
  }
4553
4516
  restoreHistory() {
@@ -4563,6 +4526,9 @@ up.Layer = class Layer extends up.Record {
4563
4526
  if (this.savedMetaTags) {
4564
4527
  up.history.updateMetaTags(this.savedMetaTags);
4565
4528
  }
4529
+ if (u.isString(this.savedLang)) {
4530
+ up.history.updateLang(this.savedLang);
4531
+ }
4566
4532
  }
4567
4533
  asCurrent(fn) {
4568
4534
  return this.stack.asCurrent(this, fn);
@@ -4578,6 +4544,9 @@ up.Layer = class Layer extends up.Record {
4578
4544
  if (u.isString(options.title)) {
4579
4545
  this.title = options.title;
4580
4546
  }
4547
+ if (u.isString(options.lang)) {
4548
+ this.lang = options.lang;
4549
+ }
4581
4550
  }
4582
4551
  showsLiveHistory() {
4583
4552
  return this.history && this.isFront();
@@ -4610,6 +4579,20 @@ up.Layer = class Layer extends up.Record {
4610
4579
  up.history.updateMetaTags(metaTags);
4611
4580
  }
4612
4581
  }
4582
+ get lang() {
4583
+ if (this.showsLiveHistory()) {
4584
+ return up.history.getLang();
4585
+ }
4586
+ else {
4587
+ return this.savedLang;
4588
+ }
4589
+ }
4590
+ set lang(lang) {
4591
+ this.savedLang = lang;
4592
+ if (this.showsLiveHistory()) {
4593
+ up.history.updateLang(lang);
4594
+ }
4595
+ }
4613
4596
  get location() {
4614
4597
  if (this.showsLiveHistory()) {
4615
4598
  return up.history.location;
@@ -5321,7 +5304,10 @@ up.LinkFeedbackURLs = class LinkFeedbackURLs {
5321
5304
  }
5322
5305
  }
5323
5306
  isCurrent(normalizedLocation) {
5324
- return this._isSafe && !!(this.href === normalizedLocation ||
5307
+ if (!normalizedLocation) {
5308
+ return false;
5309
+ }
5310
+ return !!(this.href === normalizedLocation ||
5325
5311
  this._upHREF === normalizedLocation ||
5326
5312
  this._aliasPattern?.test?.(normalizedLocation, false));
5327
5313
  }
@@ -5334,60 +5320,40 @@ up.LinkFeedbackURLs = class LinkFeedbackURLs {
5334
5320
 
5335
5321
  const u = up.util;
5336
5322
  const e = up.element;
5337
- up.LinkPreloader = class LinkPreloader {
5338
- watchLink(link) {
5339
- if (!up.link.preloadIssue(link)) {
5340
- this._on(link, 'mouseenter', (event) => this._considerPreload(event, true));
5341
- this._on(link, 'mousedown touchstart', (event) => this._considerPreload(event));
5342
- this._on(link, 'mouseleave', (event) => this._stopPreload(event));
5343
- }
5344
- }
5345
- _on(link, eventTypes, callback) {
5346
- up.on(link, eventTypes, { passive: true }, callback);
5347
- }
5348
- _considerPreload(event, applyDelay) {
5349
- const link = event.target;
5350
- if (link !== this._currentLink) {
5351
- this.reset();
5352
- this._currentLink = link;
5353
- if (up.link.shouldFollowEvent(event, link)) {
5354
- if (applyDelay) {
5355
- this._preloadAfterDelay(event, link);
5356
- }
5357
- else {
5358
- this._preloadNow(event, link);
5359
- }
5360
- }
5361
- }
5323
+ up.LinkFollowIntent = class LinkFollowIntent {
5324
+ constructor(link, callback) {
5325
+ this._link = link;
5326
+ this._callback = callback;
5327
+ this._on('mouseenter mousedown touchstart', (event) => this._scheduleCallback(event));
5328
+ this._on('mouseleave', () => this._unscheduleCallback());
5329
+ up.fragment.onAborted(this._link, () => this._unscheduleCallback());
5362
5330
  }
5363
- _stopPreload(event) {
5364
- if (event.target === this._currentLink) {
5365
- return this.reset();
5366
- }
5331
+ _on(eventType, callback) {
5332
+ up.on(this._link, eventType, { passive: true }, callback);
5367
5333
  }
5368
- reset() {
5369
- if (!this._currentLink) {
5334
+ _scheduleCallback(event) {
5335
+ if (!up.link.shouldFollowEvent(event, this._link))
5370
5336
  return;
5337
+ this._unscheduleCallback();
5338
+ const applyDelay = (event.type === 'mouseenter');
5339
+ if (applyDelay) {
5340
+ let delay = this._parseDelay();
5341
+ this._timer = u.timer(delay, () => this._runCallback(event));
5371
5342
  }
5372
- clearTimeout(this._timer);
5373
- if (this._currentRequest?.background) {
5374
- this._currentRequest.abort();
5343
+ else {
5344
+ this._runCallback(event);
5375
5345
  }
5376
- this._currentLink = undefined;
5377
- this._currentRequest = undefined;
5378
5346
  }
5379
- _preloadAfterDelay(event, link) {
5380
- const delay = e.numberAttr(link, 'up-preload-delay') ?? up.link.config.preloadDelay;
5381
- this._timer = u.timer(delay, () => this._preloadNow(event, link));
5347
+ _unscheduleCallback() {
5348
+ clearTimeout(this._timer);
5349
+ up.network.abort((request) => (request.origin === this._link) && request.background);
5382
5350
  }
5383
- _preloadNow(event, link) {
5384
- if (!link.isConnected) {
5385
- this.reset();
5386
- return;
5387
- }
5388
- const onQueued = request => { return this._currentRequest = request; };
5351
+ _parseDelay() {
5352
+ return e.numberAttr(this._link, 'up-preload-delay') ?? up.link.config.preloadDelay;
5353
+ }
5354
+ _runCallback(event) {
5389
5355
  up.log.putsEvent(event);
5390
- up.error.muteUncriticalRejection(up.link.preload(link, { onQueued }));
5356
+ up.error.muteUncriticalRejection(this._callback());
5391
5357
  }
5392
5358
  };
5393
5359
 
@@ -6130,7 +6096,6 @@ up.Request = (_a = class Request extends up.Record {
6130
6096
  'wrapMethod',
6131
6097
  'contentType',
6132
6098
  'payload',
6133
- 'onQueued',
6134
6099
  'onLoading',
6135
6100
  'fail',
6136
6101
  'abortable',
@@ -6164,7 +6129,7 @@ up.Request = (_a = class Request extends up.Record {
6164
6129
  }
6165
6130
  this.deferred = u.newDeferred();
6166
6131
  this.badResponseTime ??= u.evalOption(up.network.config.badResponseTime, this);
6167
- this._addAutoHeaders();
6132
+ this._setAutoHeaders();
6168
6133
  }
6169
6134
  get xhr() {
6170
6135
  return this._xhr ??= new XMLHttpRequest();
@@ -6173,7 +6138,7 @@ up.Request = (_a = class Request extends up.Record {
6173
6138
  if (this._fragments) {
6174
6139
  return this._fragments;
6175
6140
  }
6176
- else if (this.target) {
6141
+ else {
6177
6142
  let steps = up.fragment.parseTargetSteps(this.target);
6178
6143
  let selectors = u.map(steps, 'selector');
6179
6144
  let lookupOpts = { origin: this.origin, layer: this.layer };
@@ -6228,7 +6193,6 @@ up.Request = (_a = class Request extends up.Record {
6228
6193
  }
6229
6194
  runQueuedCallbacks() {
6230
6195
  u.always(this, () => this._evictExpensiveAttrs());
6231
- this.onQueued?.(this);
6232
6196
  }
6233
6197
  load() {
6234
6198
  if (this.state !== 'new')
@@ -6372,9 +6336,6 @@ up.Request = (_a = class Request extends up.Record {
6372
6336
  return this.method + ' ' + this.url;
6373
6337
  }
6374
6338
  isPartOfSubtree(subtreeElements) {
6375
- if (!this.fragments || !subtreeElements) {
6376
- return false;
6377
- }
6378
6339
  subtreeElements = u.wrapList(subtreeElements);
6379
6340
  return u.some(this.fragments, function (fragment) {
6380
6341
  return u.some(subtreeElements, (subtreeElement) => subtreeElement.contains(fragment));
@@ -6386,17 +6347,20 @@ up.Request = (_a = class Request extends up.Record {
6386
6347
  header(name) {
6387
6348
  return this.headers[name];
6388
6349
  }
6389
- _addAutoHeaders() {
6350
+ _setAutoHeaders() {
6390
6351
  for (let key of ['target', 'failTarget', 'mode', 'failMode', 'context', 'failContext']) {
6391
- this._addAutoHeader(up.protocol.headerize(key), this[key]);
6352
+ this._setPropertyHeader(key);
6392
6353
  }
6393
6354
  let csrfHeader, csrfToken;
6394
6355
  if ((csrfHeader = this.csrfHeader()) && (csrfToken = this.csrfToken())) {
6395
- this._addAutoHeader(csrfHeader, csrfToken);
6356
+ this._setAutoHeader(csrfHeader, csrfToken);
6396
6357
  }
6397
- this._addAutoHeader(up.protocol.headerize('version'), up.version);
6358
+ this._setAutoHeader(up.protocol.headerize('version'), up.version);
6398
6359
  }
6399
- _addAutoHeader(name, value) {
6360
+ _setPropertyHeader(key) {
6361
+ this._setAutoHeader(up.protocol.headerize(key), this[key]);
6362
+ }
6363
+ _setAutoHeader(name, value) {
6400
6364
  if (u.isMissing(value)) {
6401
6365
  return;
6402
6366
  }
@@ -6405,6 +6369,16 @@ up.Request = (_a = class Request extends up.Record {
6405
6369
  }
6406
6370
  this.headers[name] = value;
6407
6371
  }
6372
+ mergeIfUnsent(trackingRequest) {
6373
+ if (this.state !== 'new')
6374
+ return;
6375
+ if (!this.target || !trackingRequest.target)
6376
+ return;
6377
+ let targetAtoms = up.fragment.splitTarget(this.target + ',' + trackingRequest.target);
6378
+ this.target = u.uniq(targetAtoms).join(', ');
6379
+ this._setPropertyHeader('target');
6380
+ this._fragments = u.uniq([...this.fragments, ...trackingRequest.fragments]);
6381
+ }
6408
6382
  static tester(condition, { except } = {}) {
6409
6383
  let testFn;
6410
6384
  if (u.isFunction(condition)) {
@@ -6439,74 +6413,82 @@ up.Request = (_a = class Request extends up.Record {
6439
6413
  /***/ (() => {
6440
6414
 
6441
6415
  const u = up.util;
6416
+ class Route {
6417
+ constructor() {
6418
+ this.varyHeaders = new Set();
6419
+ this.requests = [];
6420
+ }
6421
+ matchBest(newRequest) {
6422
+ let matches = this.requests.filter((cachedRequest) => this.satisfies(cachedRequest, newRequest));
6423
+ return u.last(matches);
6424
+ }
6425
+ delete(request) {
6426
+ u.remove(this.requests, request);
6427
+ }
6428
+ put(request) {
6429
+ this.requests.push(request);
6430
+ }
6431
+ updateVary(response) {
6432
+ for (let headerName of response.varyHeaderNames) {
6433
+ this.varyHeaders.add(headerName);
6434
+ }
6435
+ }
6436
+ satisfies(cachedRequest, newRequest) {
6437
+ if (cachedRequest === newRequest)
6438
+ return true;
6439
+ return u.every(this.varyHeaders, (varyHeader) => {
6440
+ let cachedValue = cachedRequest.header(varyHeader);
6441
+ let newValue = newRequest.header(varyHeader);
6442
+ if (varyHeader === 'X-Up-Target' || varyHeader === 'X-Up-Fail-Target') {
6443
+ if (!cachedValue)
6444
+ return true;
6445
+ if (!newValue)
6446
+ return false;
6447
+ let cachedTokens = u.parseTokens(cachedValue, { separator: 'comma' });
6448
+ let newTokens = u.parseTokens(newValue, { separator: 'comma' });
6449
+ return u.containsAll(cachedTokens, newTokens);
6450
+ }
6451
+ else {
6452
+ return cachedValue === newValue;
6453
+ }
6454
+ });
6455
+ }
6456
+ }
6442
6457
  up.Request.Cache = class Cache {
6443
6458
  constructor() {
6444
6459
  this.reset();
6445
6460
  }
6446
6461
  reset() {
6447
- this._varyInfo = {};
6448
- this._map = new Map();
6449
- }
6450
- _cacheKey(request) {
6451
- let influencingHeaders = this._getPreviousInfluencingHeaders(request);
6452
- let varyPart = u.flatMap(influencingHeaders, (headerName) => [headerName, request.header(headerName)]);
6453
- return [request.description, ...varyPart].join(':');
6454
- }
6455
- _getPreviousInfluencingHeaders(request) {
6456
- return (this._varyInfo[request.description] ||= new Set());
6462
+ this._routes = {};
6463
+ this._requests = [];
6457
6464
  }
6458
6465
  get(request) {
6459
6466
  request = this._wrap(request);
6460
- let cacheKey = this._cacheKey(request);
6461
- let cachedRequest = this._map.get(cacheKey);
6467
+ let route = this._getRoute(request);
6468
+ let cachedRequest = route.matchBest(request);
6462
6469
  if (cachedRequest) {
6463
6470
  if (this._isUsable(cachedRequest)) {
6464
6471
  return cachedRequest;
6465
6472
  }
6466
6473
  else {
6467
- this._map.delete(cacheKey);
6474
+ this._delete(request, route);
6468
6475
  }
6469
6476
  }
6470
6477
  }
6471
- get _capacity() {
6472
- return up.network.config.cacheSize;
6473
- }
6474
- _isUsable(request) {
6475
- return request.age < up.network.config.cacheEvictAge;
6476
- }
6477
6478
  async put(request) {
6478
6479
  request = this._wrap(request);
6479
- this._makeRoom();
6480
- let cacheKey = this._updateCacheKey(request);
6481
- this._map.set(cacheKey, request);
6482
- }
6483
- _updateCacheKey(request) {
6484
- let oldCacheKey = this._cacheKey(request);
6480
+ let route = this._getRoute(request);
6485
6481
  let { response } = request;
6486
- if (response) {
6487
- this._mergePreviousHeaderNames(request, response);
6488
- let newCacheKey = this._cacheKey(request);
6489
- this._renameMapKey(oldCacheKey, newCacheKey);
6490
- return newCacheKey;
6491
- }
6492
- else {
6493
- return oldCacheKey;
6494
- }
6495
- }
6496
- _renameMapKey(oldKey, newKey) {
6497
- if (oldKey !== newKey && this._map.has(oldKey)) {
6498
- this._map.set(newKey, this._map.get(oldKey));
6499
- this._map.delete(oldKey);
6500
- }
6501
- }
6502
- _mergePreviousHeaderNames(request, response) {
6503
- let headersInfluencingResponse = response.ownInfluncingHeaders;
6504
- if (headersInfluencingResponse.length) {
6505
- let previousInfluencingHeaders = this._getPreviousInfluencingHeaders(request);
6506
- for (let headerName of headersInfluencingResponse) {
6507
- previousInfluencingHeaders.add(headerName);
6508
- }
6482
+ if (response)
6483
+ route.updateVary(response);
6484
+ let superseded = route.requests.filter((oldRequest) => route.satisfies(request, oldRequest));
6485
+ for (let r of superseded) {
6486
+ this._delete(r);
6509
6487
  }
6488
+ request.cacheRoute = route;
6489
+ route.put(request);
6490
+ this._requests.push(request);
6491
+ this._limitSize();
6510
6492
  }
6511
6493
  alias(existingCachedRequest, newRequest) {
6512
6494
  existingCachedRequest = this.get(existingCachedRequest);
@@ -6522,7 +6504,7 @@ up.Request.Cache = class Cache {
6522
6504
  newRequest.state = 'tracking';
6523
6505
  let value = await u.always(existingRequest);
6524
6506
  if (value instanceof up.Response) {
6525
- if (options.force || this._isCacheCompatible(existingRequest, newRequest)) {
6507
+ if (options.force || existingRequest.cacheRoute.satisfies(existingRequest, newRequest)) {
6526
6508
  newRequest.fromCache = true;
6527
6509
  value = u.variant(value, { request: newRequest });
6528
6510
  newRequest.respondWith(value);
@@ -6542,31 +6524,43 @@ up.Request.Cache = class Cache {
6542
6524
  willHaveSameResponse(existingRequest, newRequest) {
6543
6525
  return existingRequest === newRequest || existingRequest === newRequest.trackedRequest;
6544
6526
  }
6545
- _delete(request) {
6546
- request = this._wrap(request);
6547
- let cacheKey = this._cacheKey(request);
6548
- this._map.delete(cacheKey);
6549
- }
6550
6527
  evict(condition = true, testerOptions) {
6551
6528
  this._eachMatch(condition, testerOptions, (request) => this._delete(request));
6552
6529
  }
6553
6530
  expire(condition = true, testerOptions) {
6554
6531
  this._eachMatch(condition, testerOptions, (request) => request.expired = true);
6555
6532
  }
6556
- _makeRoom() {
6557
- while (this._map.size >= this._capacity) {
6558
- let oldestKey = this._map.keys().next().value;
6559
- this._map.delete(oldestKey);
6533
+ reindex(request) {
6534
+ this._delete(request);
6535
+ this.put(request);
6536
+ }
6537
+ _delete(request) {
6538
+ u.remove(this._requests, request);
6539
+ request.cacheRoute?.delete(request);
6540
+ delete request.cacheRoute;
6541
+ }
6542
+ _getRoute(request) {
6543
+ return request.cacheRoute || (this._routes[request.description] ||= new Route());
6544
+ }
6545
+ _isUsable(request) {
6546
+ return request.age < up.network.config.cacheEvictAge;
6547
+ }
6548
+ get _size() {
6549
+ return this._requests.length;
6550
+ }
6551
+ get _capacity() {
6552
+ return up.network.config.cacheSize;
6553
+ }
6554
+ _limitSize() {
6555
+ for (let i = 0; i < (this._size - this._capacity); i++) {
6556
+ this._delete(this._requests[0]);
6560
6557
  }
6561
6558
  }
6562
6559
  _eachMatch(condition = true, testerOptions, fn) {
6563
6560
  let tester = up.Request.tester(condition, testerOptions);
6564
- let results = u.filter(this._map.values(), tester);
6561
+ let results = u.filter(this._requests, tester);
6565
6562
  u.each(results, fn);
6566
6563
  }
6567
- _isCacheCompatible(request1, request2) {
6568
- return this._cacheKey(request1) === this._cacheKey(request2);
6569
- }
6570
6564
  _wrap(requestOrOptions) {
6571
6565
  return u.wrapValue(up.Request, requestOrOptions);
6572
6566
  }
@@ -6595,7 +6589,7 @@ up.Request.Queue = class Queue {
6595
6589
  u.always(request, responseOrError => this._onRequestSettled(request, responseOrError));
6596
6590
  this._scheduleSlowTimer(request);
6597
6591
  this._queueRequest(request);
6598
- u.microtask(() => this._poke());
6592
+ queueMicrotask(() => this._poke());
6599
6593
  }
6600
6594
  promoteToForeground(request) {
6601
6595
  if (request.background) {
@@ -6636,7 +6630,7 @@ up.Request.Queue = class Queue {
6636
6630
  up.network.registerAliasForRedirect(request, responseOrError);
6637
6631
  }
6638
6632
  this._checkLate();
6639
- u.microtask(() => this._poke());
6633
+ queueMicrotask(() => this._poke());
6640
6634
  }
6641
6635
  _poke() {
6642
6636
  let request;
@@ -6830,15 +6824,12 @@ up.Response = class Response extends up.Record {
6830
6824
  get none() {
6831
6825
  return !this.text;
6832
6826
  }
6833
- isCacheable() {
6834
- return this.ok && !this.none;
6835
- }
6836
6827
  header(name) {
6837
6828
  return this.headers[name] || this.xhr?.getResponseHeader(name);
6838
6829
  }
6839
- get ownInfluncingHeaders() {
6840
- let influencingHeaders = up.protocol.influencingHeadersFromResponse(this);
6841
- return u.filter(influencingHeaders, (headerName) => this.request.header(headerName));
6830
+ get varyHeaderNames() {
6831
+ let varyHeaderValue = this.header('Vary');
6832
+ return u.parseTokens(varyHeaderValue, { separator: 'comma' });
6842
6833
  }
6843
6834
  get contentType() {
6844
6835
  return this.header('Content-Type');
@@ -6879,6 +6870,7 @@ up.Response = class Response extends up.Record {
6879
6870
  var _a;
6880
6871
  const u = up.util;
6881
6872
  const e = up.element;
6873
+ const FULL_DOCUMENT_PATTERN = /^\s*<(html|!DOCTYPE)\b/i;
6882
6874
  up.ResponseDoc = (_a = class ResponseDoc {
6883
6875
  constructor({ document, fragment, content, target, origin, cspNonces, match }) {
6884
6876
  if (document) {
@@ -6899,43 +6891,43 @@ up.ResponseDoc = (_a = class ResponseDoc {
6899
6891
  }
6900
6892
  this._match = match;
6901
6893
  }
6902
- _parseDocument(document) {
6903
- document = this._parse(document, e.createBrokenDocumentFromHTML);
6904
- this._isDocumentBroken = true;
6905
- this._useParseResult(document);
6906
- }
6907
- _parseFragment(fragment) {
6908
- fragment = this._parse(fragment, e.createFromHTML);
6909
- this._useParseResult(fragment);
6910
- }
6911
- _parseContent(content, target) {
6912
- if (!target)
6913
- up.fail("must pass a { target } when passing { content }");
6914
- target = u.map(up.fragment.parseTargetSteps(target), 'selector').join();
6915
- const matchingElement = e.createFromSelector(target);
6916
- if (u.isString(content)) {
6917
- matchingElement.innerHTML = content;
6894
+ _parseDocument(value) {
6895
+ if (value instanceof Document) {
6896
+ this._document = value;
6897
+ this._isFullDocument = true;
6898
+ }
6899
+ else if (u.isString(value)) {
6900
+ this._document = e.createBrokenDocumentFromHTML(value);
6901
+ this._isFullDocument = FULL_DOCUMENT_PATTERN.test(value);
6902
+ this._isDocumentBroken = true;
6918
6903
  }
6919
6904
  else {
6920
- matchingElement.appendChild(content);
6905
+ this._document = this._buildFauxDocument(value);
6906
+ this._isFullDocument = value.matches('html');
6921
6907
  }
6922
- this._useParseResult(matchingElement);
6923
6908
  }
6924
- _parse(value, parseFn) {
6925
- if (u.isString(value)) {
6926
- value = parseFn(value);
6927
- }
6928
- return value;
6909
+ _parseFragment(value) {
6910
+ let parsed = u.isString(value) ? e.createFromHTML(value) : value;
6911
+ this._document = this._buildFauxDocument(parsed);
6929
6912
  }
6930
- _useParseResult(node) {
6931
- if (node instanceof Document) {
6932
- this._document = node;
6913
+ _parseContent(value, target) {
6914
+ if (!target)
6915
+ up.fail("must pass a { target } when passing { content }");
6916
+ let simplifiedTarget = u.map(up.fragment.parseTargetSteps(target), 'selector').join();
6917
+ const matchingElement = e.createFromSelector(simplifiedTarget);
6918
+ if (u.isString(value)) {
6919
+ matchingElement.innerHTML = value;
6933
6920
  }
6934
6921
  else {
6935
- this._document = document.createElement('up-document');
6936
- this._document.append(node);
6937
- this._document.documentElement = node;
6922
+ matchingElement.appendChild(value);
6938
6923
  }
6924
+ this._document = this._buildFauxDocument(matchingElement);
6925
+ }
6926
+ _buildFauxDocument(node) {
6927
+ let fauxDocument = document.createElement('up-document');
6928
+ fauxDocument.append(node);
6929
+ fauxDocument.documentElement = node;
6930
+ return fauxDocument;
6939
6931
  }
6940
6932
  rootSelector() {
6941
6933
  return up.fragment.toTarget(this._document.documentElement);
@@ -6944,9 +6936,8 @@ up.ResponseDoc = (_a = class ResponseDoc {
6944
6936
  return this._fromHead(this._getTitleText);
6945
6937
  }
6946
6938
  _getHead() {
6947
- let { head } = this._document;
6948
- if (head && head.childNodes.length > 0) {
6949
- return head;
6939
+ if (this._isFullDocument) {
6940
+ return this._document.head;
6950
6941
  }
6951
6942
  }
6952
6943
  _fromHead(fn) {
@@ -6959,6 +6950,11 @@ up.ResponseDoc = (_a = class ResponseDoc {
6959
6950
  get assets() {
6960
6951
  return this._fromHead(up.script.findAssets);
6961
6952
  }
6953
+ get lang() {
6954
+ if (this._isFullDocument) {
6955
+ return up.history.getLang(this._document);
6956
+ }
6957
+ }
6962
6958
  _getTitleText(head) {
6963
6959
  return head.querySelector('title')?.textContent;
6964
6960
  }
@@ -7056,7 +7052,7 @@ up.RevealMotion = class RevealMotion {
7056
7052
  const maxPixels = u.evalOption(this._max, this._element);
7057
7053
  elementRect.height = Math.min(elementRect.height, maxPixels);
7058
7054
  }
7059
- this._addPadding(elementRect);
7055
+ elementRect.grow(this._padding);
7060
7056
  this._substractObstructions(viewportRect);
7061
7057
  if (viewportRect.height < 0) {
7062
7058
  up.fail('Viewport has no visible area');
@@ -7095,10 +7091,6 @@ up.RevealMotion = class RevealMotion {
7095
7091
  return up.Rect.fromElement(this._viewport);
7096
7092
  }
7097
7093
  }
7098
- _addPadding(elementRect) {
7099
- elementRect.top -= this._padding;
7100
- elementRect.height += 2 * this._padding;
7101
- }
7102
7094
  _selectObstructions(selector) {
7103
7095
  let elements = up.fragment.all(selector, { layer: this._obstructionsLayer });
7104
7096
  return u.filter(elements, e.isVisible);
@@ -7234,10 +7226,10 @@ up.Tether = class Tether {
7234
7226
  sync() {
7235
7227
  const elementBox = this._element.getBoundingClientRect();
7236
7228
  const elementMargin = {
7237
- top: e.styleNumber(this._element, 'marginTop'),
7238
- right: e.styleNumber(this._element, 'marginRight'),
7239
- bottom: e.styleNumber(this._element, 'marginBottom'),
7240
- left: e.styleNumber(this._element, 'marginLeft')
7229
+ top: e.styleNumber(this._element, 'margin-top'),
7230
+ right: e.styleNumber(this._element, 'margin-right'),
7231
+ bottom: e.styleNumber(this._element, 'margin-bottom'),
7232
+ left: e.styleNumber(this._element, 'margin-left')
7241
7233
  };
7242
7234
  const anchorBox = this._anchor.getBoundingClientRect();
7243
7235
  let left;
@@ -7305,7 +7297,7 @@ up.Tether = class Tether {
7305
7297
  _setOffset(left, top) {
7306
7298
  this.offsetLeft = left;
7307
7299
  this.offsetTop = top;
7308
- e.setStyle(this._element, { left, top });
7300
+ e.setStyle(this._element, { left, top }, 'px');
7309
7301
  }
7310
7302
  };
7311
7303
 
@@ -7646,10 +7638,6 @@ up.protocol = (function () {
7646
7638
  function locationFromXHR(xhr) {
7647
7639
  return extractHeader(xhr, 'location') || xhr.responseURL;
7648
7640
  }
7649
- function influencingHeadersFromResponse(response) {
7650
- let varyHeaderValue = response.header('Vary');
7651
- return u.parseTokens(varyHeaderValue, { separator: 'comma' });
7652
- }
7653
7641
  const config = new up.Config(() => ({
7654
7642
  methodParam: '_method',
7655
7643
  csrfParam() { return e.metaContent('csrf-param'); },
@@ -7710,7 +7698,6 @@ up.protocol = (function () {
7710
7698
  headerize,
7711
7699
  wrapMethod,
7712
7700
  cspNoncesFromHeader,
7713
- influencingHeadersFromResponse,
7714
7701
  };
7715
7702
  })();
7716
7703
 
@@ -7846,44 +7833,61 @@ up.script = (function () {
7846
7833
  let registeredCompilers = [];
7847
7834
  let registeredMacros = [];
7848
7835
  function registerCompiler(...args) {
7849
- const compiler = buildCompiler(args);
7850
- return insertCompiler(registeredCompilers, compiler);
7836
+ registerProcessor(args);
7851
7837
  }
7852
7838
  function registerMacro(...args) {
7853
- const macro = buildCompiler(args);
7854
- if (up.framework.evaling) {
7855
- macro.priority ||= detectSystemMacroPriority(macro.selector) ||
7856
- up.fail('Unregistered priority for system macro %o', macro.selector);
7857
- }
7858
- return insertCompiler(registeredMacros, macro);
7839
+ registerProcessor(args, { macro: true });
7840
+ }
7841
+ function registerAttrCompiler(...args) {
7842
+ let [attr, options, valueCallback] = parseProcessorArgs(args);
7843
+ let selector = `[${attr}]`;
7844
+ let callback = (element) => {
7845
+ let value = e.booleanOrStringAttr(element, attr, options.defaultValue);
7846
+ if (!value)
7847
+ return;
7848
+ return valueCallback(element, value);
7849
+ };
7850
+ registerProcessor([selector, options, callback]);
7859
7851
  }
7860
7852
  function detectSystemMacroPriority(macroSelector) {
7861
7853
  macroSelector = u.evalOption(macroSelector);
7862
7854
  for (let substr in SYSTEM_MACRO_PRIORITIES) {
7863
- const priority = SYSTEM_MACRO_PRIORITIES[substr];
7864
7855
  if (macroSelector.indexOf(substr) >= 0) {
7865
- return priority;
7856
+ return SYSTEM_MACRO_PRIORITIES[substr];
7866
7857
  }
7867
7858
  }
7859
+ up.fail('Unregistered priority for system macro %o', macroSelector);
7868
7860
  }
7869
- const parseCompilerArgs = function (args) {
7861
+ function registerProcessor(args, overrides = {}) {
7862
+ let processor = buildProcessor(args, overrides);
7863
+ if (processor.macro) {
7864
+ if (up.framework.evaling) {
7865
+ processor.priority ||= detectSystemMacroPriority(processor.selector);
7866
+ }
7867
+ insertProcessor(registeredMacros, processor);
7868
+ }
7869
+ else {
7870
+ insertProcessor(registeredCompilers, processor);
7871
+ }
7872
+ }
7873
+ const parseProcessorArgs = function (args) {
7870
7874
  const defaults = u.extractOptions(args);
7871
7875
  const selector = args.shift();
7872
7876
  const callback = args.pop();
7873
7877
  const options = { ...defaults, ...u.extractOptions(args) };
7874
7878
  return [selector, options, callback];
7875
7879
  };
7876
- function buildCompiler(args) {
7877
- let [selector, options, callback] = parseCompilerArgs(args);
7880
+ function buildProcessor(args, overrides) {
7881
+ let [selector, options, callback] = parseProcessorArgs(args);
7878
7882
  options = u.options(options, {
7879
7883
  selector,
7880
7884
  isDefault: up.framework.evaling,
7881
7885
  priority: 0,
7882
7886
  batch: false,
7883
7887
  });
7884
- return Object.assign(callback, options);
7888
+ return Object.assign(callback, options, overrides);
7885
7889
  }
7886
- function insertCompiler(queue, newCompiler) {
7890
+ function insertProcessor(queue, newCompiler) {
7887
7891
  let existingCompiler;
7888
7892
  let index = 0;
7889
7893
  while ((existingCompiler = queue[index]) && (existingCompiler.priority >= newCompiler.priority)) {
@@ -7981,6 +7985,7 @@ up.script = (function () {
7981
7985
  config,
7982
7986
  compiler: registerCompiler,
7983
7987
  macro: registerMacro,
7988
+ attrCompiler: registerAttrCompiler,
7984
7989
  destructor: registerDestructor,
7985
7990
  hello,
7986
7991
  clean,
@@ -7995,6 +8000,7 @@ up.destructor = up.script.destructor;
7995
8000
  up.macro = up.script.macro;
7996
8001
  up.data = up.script.data;
7997
8002
  up.hello = up.script.hello;
8003
+ up.attribute = up.script.attrCompiler;
7998
8004
 
7999
8005
 
8000
8006
  /***/ }),
@@ -8084,10 +8090,8 @@ up.history = (function () {
8084
8090
  return;
8085
8091
  }
8086
8092
  let location = currentLocation();
8087
- if (up.emit('up:location:restore', { location, log: `Restoring location ${location}` }).defaultPrevented) {
8088
- return;
8089
- }
8090
8093
  up.render({
8094
+ guardEvent: up.event.build('up:location:restore', { location, log: `Restoring location ${location}` }),
8091
8095
  url: location,
8092
8096
  target: config.restoreTargets,
8093
8097
  fail: false,
@@ -8095,7 +8099,8 @@ up.history = (function () {
8095
8099
  location,
8096
8100
  peel: true,
8097
8101
  layer: 'root',
8098
- cache: true,
8102
+ cache: 'auto',
8103
+ revalidate: 'auto',
8099
8104
  saveScroll: false,
8100
8105
  scroll: ['restore', 'auto'],
8101
8106
  saveFocus: false,
@@ -8136,6 +8141,15 @@ up.history = (function () {
8136
8141
  document.head.append(newMetaTag);
8137
8142
  }
8138
8143
  }
8144
+ function getLang(doc = document) {
8145
+ let { documentElement } = doc;
8146
+ if (documentElement.matches('html')) {
8147
+ return doc.documentElement.lang;
8148
+ }
8149
+ }
8150
+ function updateLang(newLang) {
8151
+ e.toggleAttr(e.root, 'lang', newLang, !!newLang);
8152
+ }
8139
8153
  up.macro('a[up-back], [up-href][up-back]', function (link) {
8140
8154
  if (previousLocation) {
8141
8155
  e.setMissingAttrs(link, {
@@ -8157,6 +8171,8 @@ up.history = (function () {
8157
8171
  isLocation,
8158
8172
  findMetaTags,
8159
8173
  updateMetaTags,
8174
+ getLang,
8175
+ updateLang,
8160
8176
  };
8161
8177
  })();
8162
8178
 
@@ -8639,6 +8655,25 @@ up.fragment = (function () {
8639
8655
  up.destructor(fragment, unsubscribe);
8640
8656
  return unsubscribe;
8641
8657
  }
8658
+ function onFirstIntersect(origin, callback, { margin = 0 } = {}) {
8659
+ if (e.isIntersectingWindow(origin, { margin })) {
8660
+ callback();
8661
+ return;
8662
+ }
8663
+ function processIntersectEntries(entries) {
8664
+ for (let entry of entries) {
8665
+ if (entry.isIntersecting) {
8666
+ disconnect();
8667
+ callback();
8668
+ return;
8669
+ }
8670
+ }
8671
+ }
8672
+ let observer = new IntersectionObserver(processIntersectEntries, { rootMargin: `${margin}px` });
8673
+ let disconnect = () => observer.disconnect();
8674
+ observer.observe(origin);
8675
+ onAborted(origin, disconnect);
8676
+ }
8642
8677
  up.on('up:framework:boot', function () {
8643
8678
  const { documentElement } = document;
8644
8679
  documentElement.setAttribute('up-source', u.normalizeURL(location.href, { hash: false }));
@@ -8679,6 +8714,7 @@ up.fragment = (function () {
8679
8714
  shouldRevalidate,
8680
8715
  abort,
8681
8716
  onAborted,
8717
+ onFirstIntersect,
8682
8718
  splitTarget,
8683
8719
  parseTargetSteps,
8684
8720
  isAlive,
@@ -8810,33 +8846,9 @@ up.viewport = (function () {
8810
8846
  function isRoot(element) {
8811
8847
  return element === getRoot();
8812
8848
  }
8813
- function rootHasReducedWidthFromScrollbar() {
8814
- return window.innerWidth > document.documentElement.offsetWidth;
8815
- }
8816
- function rootOverflowElement() {
8817
- const { body } = document;
8818
- const html = document.documentElement;
8819
- const element = u.find([html, body], wasChosenAsOverflowingElement);
8820
- return element || getRoot();
8821
- }
8822
- function wasChosenAsOverflowingElement(element) {
8823
- const overflowY = e.style(element, 'overflow-y');
8824
- return overflowY === 'auto' || overflowY === 'scroll';
8825
- }
8826
- const scrollbarWidth = u.memoize(function () {
8827
- const outerStyle = {
8828
- position: 'absolute',
8829
- top: '0',
8830
- left: '0',
8831
- width: '100px',
8832
- height: '100px',
8833
- overflowY: 'scroll'
8834
- };
8835
- const outer = up.element.affix(document.body, '[up-viewport]', { style: outerStyle });
8836
- const width = outer.offsetWidth - outer.clientWidth;
8837
- outer.remove();
8838
- return width;
8839
- });
8849
+ function rootScrollbarWidth() {
8850
+ return window.innerWidth - rootWidth();
8851
+ }
8840
8852
  function scrollTopKey(viewport) {
8841
8853
  return up.fragment.tryToTarget(viewport);
8842
8854
  }
@@ -8952,7 +8964,7 @@ up.viewport = (function () {
8952
8964
  const moveBounds = function (diffX, diffY) {
8953
8965
  boundsRect.left += diffX;
8954
8966
  boundsRect.top += diffY;
8955
- return e.setStyle(bounds, boundsRect);
8967
+ return e.setStyle(bounds, boundsRect, 'px');
8956
8968
  };
8957
8969
  moveBounds(0, 0);
8958
8970
  const newElementRect = element.getBoundingClientRect();
@@ -9013,10 +9025,8 @@ up.viewport = (function () {
9013
9025
  get root() { return getRoot(); },
9014
9026
  rootWidth,
9015
9027
  rootHeight,
9016
- rootHasReducedWidthFromScrollbar,
9017
- rootOverflowElement,
9018
9028
  isRoot,
9019
- scrollbarWidth,
9029
+ rootScrollbarWidth,
9020
9030
  saveScroll,
9021
9031
  restoreScroll,
9022
9032
  resetScroll,
@@ -9095,13 +9105,15 @@ up.motion = (function () {
9095
9105
  return Promise.resolve();
9096
9106
  }
9097
9107
  function animateNow(element, lastFrame, options) {
9108
+ if (up.migrate.loaded)
9109
+ lastFrame = up.migrate.fixStyleProps(lastFrame);
9098
9110
  options = { ...options, finishEvent: motionController.finishEvent };
9099
9111
  const cssTransition = new up.CSSTransition(element, lastFrame, options);
9100
9112
  return cssTransition.start();
9101
9113
  }
9102
9114
  function applyConfig(options) {
9103
- options.easing ||= config.easing;
9104
- options.duration ||= config.duration;
9115
+ options.easing ??= config.easing;
9116
+ options.duration ??= config.duration;
9105
9117
  }
9106
9118
  function findNamedAnimation(name) {
9107
9119
  return namedAnimations[name] || up.fail("Unknown animation %o", name);
@@ -9249,7 +9261,7 @@ up.motion = (function () {
9249
9261
  return { transform: `translate(${dx}px, ${dy}px)` };
9250
9262
  }
9251
9263
  function noTranslateCSS() {
9252
- return { transform: null };
9264
+ return { transform: '' };
9253
9265
  }
9254
9266
  function untranslatedBox(element) {
9255
9267
  e.setStyle(element, noTranslateCSS());
@@ -9368,6 +9380,7 @@ up.network = (function () {
9368
9380
  if (!newRequest.background) {
9369
9381
  queue.promoteToForeground(cachedRequest);
9370
9382
  }
9383
+ cachedRequest.mergeIfUnsent(newRequest);
9371
9384
  cache.track(cachedRequest, newRequest, { onIncompatible: processRequest });
9372
9385
  return true;
9373
9386
  }
@@ -9380,7 +9393,7 @@ up.network = (function () {
9380
9393
  function handleCaching(request) {
9381
9394
  if (request.willCache()) {
9382
9395
  cache.put(request);
9383
- request.onLoading = () => cache.put(request);
9396
+ request.onLoading = () => cache.reindex(request);
9384
9397
  }
9385
9398
  u.always(request, function (responseOrError) {
9386
9399
  let expireCache = responseOrError.expireCache ?? request.expireCache ?? u.evalOption(config.expireCache, request, responseOrError);
@@ -9391,12 +9404,21 @@ up.network = (function () {
9391
9404
  if (evictCache) {
9392
9405
  cache.evict(evictCache, { except: request });
9393
9406
  }
9394
- if (cache.get(request)) {
9395
- cache.put(request);
9407
+ let hasCacheEntry = cache.get(request);
9408
+ let isResponse = responseOrError instanceof up.Response;
9409
+ let isNetworkError = !isResponse;
9410
+ let isSuccessResponse = isResponse && responseOrError.ok;
9411
+ let isErrorResponse = isResponse && !responseOrError.ok;
9412
+ let isEmptyResponse = isResponse && responseOrError.none;
9413
+ if (isErrorResponse) {
9414
+ cache.evict(request.url);
9396
9415
  }
9397
- if (!responseOrError.isCacheable?.()) {
9416
+ else if (isNetworkError || isEmptyResponse) {
9398
9417
  cache.evict(request);
9399
9418
  }
9419
+ else if (isSuccessResponse && hasCacheEntry) {
9420
+ cache.put(request);
9421
+ }
9400
9422
  });
9401
9423
  }
9402
9424
  function isBusy() {
@@ -9413,7 +9435,8 @@ up.network = (function () {
9413
9435
  if (request.cache && response.url && request.url !== response.url) {
9414
9436
  const newRequest = u.variant(request, {
9415
9437
  method: response.method,
9416
- url: response.url
9438
+ url: response.url,
9439
+ cacheRoute: null,
9417
9440
  });
9418
9441
  cache.alias(request, newRequest);
9419
9442
  }
@@ -9717,7 +9740,6 @@ __webpack_require__(96);
9717
9740
  up.link = (function () {
9718
9741
  const u = up.util;
9719
9742
  const e = up.element;
9720
- const linkPreloader = new up.LinkPreloader();
9721
9743
  let lastMousedownTarget = null;
9722
9744
  const LINKS_WITH_LOCAL_HTML = ['a[up-content]', 'a[up-fragment]', 'a[up-document]'];
9723
9745
  const LINKS_WITH_REMOTE_HTML = ['a[href]', '[up-href]'];
@@ -9751,10 +9773,9 @@ up.link = (function () {
9751
9773
  }
9752
9774
  function reset() {
9753
9775
  lastMousedownTarget = null;
9754
- linkPreloader.reset();
9755
9776
  }
9756
- const follow = up.mockable(function (link, options) {
9757
- return up.render(followOptions(link, options));
9777
+ const follow = up.mockable(function (link, options, parserOptions) {
9778
+ return up.render(followOptions(link, options, parserOptions));
9758
9779
  });
9759
9780
  function parseRequestOptions(link, options, parserOptions) {
9760
9781
  options = u.options(options);
@@ -9829,10 +9850,9 @@ up.link = (function () {
9829
9850
  parser.booleanOrString('location');
9830
9851
  parser.booleanOrString('title');
9831
9852
  parser.boolean('metaTags');
9853
+ parser.booleanOrString('lang');
9832
9854
  parser.include(up.motion.motionOptions);
9833
- if (!options.guardEvent) {
9834
- options.guardEvent = up.event.build('up:link:follow', { log: 'Following link' });
9835
- }
9855
+ options.guardEvent ??= up.event.build('up:link:follow', { log: ['Following link %o', link] });
9836
9856
  return options;
9837
9857
  }
9838
9858
  function preload(link, options) {
@@ -9876,9 +9896,10 @@ up.link = (function () {
9876
9896
  if (link.matches('a[href], button')) {
9877
9897
  return;
9878
9898
  }
9899
+ let role = link.matches('a') ? 'link' : 'button';
9879
9900
  e.setMissingAttrs(link, {
9880
9901
  tabindex: '0',
9881
- role: 'link',
9902
+ role,
9882
9903
  'up-clickable': ''
9883
9904
  });
9884
9905
  link.addEventListener('keydown', function (event) {
@@ -9938,6 +9959,42 @@ up.link = (function () {
9938
9959
  const method = followMethod(link);
9939
9960
  return up.network.isSafeMethod(method);
9940
9961
  }
9962
+ function onLoadCondition(condition, link, callback) {
9963
+ switch (condition) {
9964
+ case 'insert':
9965
+ callback();
9966
+ break;
9967
+ case 'reveal': {
9968
+ let margin = e.numberAttr(link, 'up-intersect-margin');
9969
+ up.fragment.onFirstIntersect(link, callback, { margin });
9970
+ break;
9971
+ }
9972
+ case 'hover':
9973
+ new up.LinkFollowIntent(link, callback);
9974
+ break;
9975
+ case 'manual':
9976
+ break;
9977
+ }
9978
+ }
9979
+ function loadDeferred(link, options) {
9980
+ let guardEvent = up.event.build('up:deferred:load', { log: ['Loading deferred %o', link] });
9981
+ let forcedOptions = {
9982
+ navigate: false,
9983
+ guardEvent,
9984
+ ...options,
9985
+ };
9986
+ let defaults = {
9987
+ target: ':origin',
9988
+ cache: 'auto',
9989
+ revalidate: 'auto',
9990
+ feedback: true,
9991
+ };
9992
+ return follow(link, forcedOptions, { defaults });
9993
+ }
9994
+ up.attribute('up-defer', { defaultValue: 'insert' }, function (link, condition) {
9995
+ let doLoad = () => up.error.muteUncriticalRejection(loadDeferred(link));
9996
+ onLoadCondition(condition, link, doLoad);
9997
+ });
9941
9998
  up.on('up:click', config.selectorFn('followSelectors'), function (event, link) {
9942
9999
  if (shouldFollowEvent(event, link)) {
9943
10000
  up.event.halt(event, { log: true });
@@ -9945,21 +10002,22 @@ up.link = (function () {
9945
10002
  up.error.muteUncriticalRejection(follow(link));
9946
10003
  }
9947
10004
  });
9948
- up.macro('[up-expand]', function (area) {
9949
- const selector = area.getAttribute('up-expand') || 'a, [up-href]';
9950
- let childLink = e.get(area, selector);
10005
+ up.attribute('up-expand', { defaultValue: 'a, [up-href]', macro: true }, function (area, childLinkSelector) {
10006
+ let childLink = e.get(area, childLinkSelector);
9951
10007
  if (childLink) {
9952
- const areaAttrs = e.upAttrs(childLink);
9953
- areaAttrs['up-href'] ||= childLink.getAttribute('href');
9954
- e.setMissingAttrs(area, areaAttrs);
9955
- const areaClasses = e.upClasses(childLink);
9956
- area.classList.add(...areaClasses);
10008
+ e.setMissingAttrs(area, {
10009
+ 'up-href': e.attr(childLink, 'href'),
10010
+ ...e.upAttrs(childLink)
10011
+ });
10012
+ area.classList.add(...e.upClasses(childLink));
9957
10013
  makeFollowable(area);
9958
10014
  }
9959
10015
  });
9960
10016
  up.compiler(config.selectorFn('preloadSelectors'), function (link) {
9961
10017
  if (!isPreloadDisabled(link)) {
9962
- linkPreloader.watchLink(link);
10018
+ let doPreload = () => up.error.muteUncriticalRejection(preload(link));
10019
+ let condition = e.booleanOrStringAttr(link, 'up-preload', null) ?? 'hover';
10020
+ onLoadCondition(condition, link, doPreload);
9963
10021
  }
9964
10022
  });
9965
10023
  up.on('up:framework:reset', reset);
@@ -9968,18 +10026,17 @@ up.link = (function () {
9968
10026
  followOptions,
9969
10027
  preload,
9970
10028
  makeFollowable,
9971
- makeClickable,
9972
10029
  isSafe,
9973
10030
  isFollowable,
9974
10031
  shouldFollowEvent,
9975
- followMethod,
9976
10032
  convertClicks,
9977
10033
  config,
9978
10034
  combineFollowableSelectors,
9979
- preloadIssue,
10035
+ loadDeferred,
9980
10036
  };
9981
10037
  })();
9982
10038
  up.follow = up.link.follow;
10039
+ up.deferred = { load: up.link.loadDeferred };
9983
10040
 
9984
10041
 
9985
10042
  /***/ }),
@@ -10055,7 +10112,8 @@ up.form = (function () {
10055
10112
  options.guardEvent ||= up.event.build('up:form:submit', {
10056
10113
  submitButton: options.submitButton,
10057
10114
  log: 'Submitting form',
10058
- params: options.params
10115
+ params: options.params,
10116
+ form,
10059
10117
  });
10060
10118
  options.origin ||= up.viewport.focusedElementWithin(form) || options.submitButton || form;
10061
10119
  parser.include(up.link.followOptions);
@@ -10328,7 +10386,9 @@ up.form = (function () {
10328
10386
  validator.watchContainer(fieldOrForm);
10329
10387
  });
10330
10388
  function validatingFieldSelector() {
10331
- return config.fieldSelectors.map((selector) => `${selector}[up-validate], [up-validate] ${selector}`).join(', ');
10389
+ let includes = config.fieldSelectors.map((selector) => `${selector}[up-validate], [up-validate] ${selector}`);
10390
+ let excludes = ['[up-validate=false]'];
10391
+ return e.unionSelector(includes, excludes);
10332
10392
  }
10333
10393
  up.compiler('[up-switch]', (switcher) => {
10334
10394
  switchTargets(switcher);
@@ -10339,8 +10399,8 @@ up.form = (function () {
10339
10399
  up.compiler('[up-show-for]:not(.up-switched), [up-hide-for]:not(.up-switched)', (element) => {
10340
10400
  switchTarget(element);
10341
10401
  });
10342
- up.compiler('[up-watch]', (formOrField) => watch(formOrField));
10343
- up.compiler('[up-autosubmit]', (formOrField) => autosubmit(formOrField));
10402
+ up.attribute('up-watch', (formOrField) => watch(formOrField));
10403
+ up.attribute('up-autosubmit', (formOrField) => autosubmit(formOrField));
10344
10404
  return {
10345
10405
  config,
10346
10406
  submit,
@@ -10382,6 +10442,7 @@ up.feedback = (function () {
10382
10442
  const config = new up.Config(() => ({
10383
10443
  currentClasses: ['up-current'],
10384
10444
  navSelectors: ['[up-nav]', 'nav'],
10445
+ noNavSelectors: ['[up-nav=false]'],
10385
10446
  }));
10386
10447
  function reset() {
10387
10448
  up.layer.root.feedbackLocation = null;
@@ -10389,9 +10450,6 @@ up.feedback = (function () {
10389
10450
  const CLASS_ACTIVE = 'up-active';
10390
10451
  const CLASS_LOADING = 'up-loading';
10391
10452
  const SELECTOR_LINK = 'a, [up-href]';
10392
- function navSelector() {
10393
- return config.selector('navSelectors');
10394
- }
10395
10453
  function normalizeURL(url) {
10396
10454
  if (url) {
10397
10455
  return u.normalizeURL(url, { trailingSlash: false, hash: false });
@@ -10400,40 +10458,23 @@ up.feedback = (function () {
10400
10458
  function linkURLs(link) {
10401
10459
  return link.upFeedbackURLs ||= new up.LinkFeedbackURLs(link);
10402
10460
  }
10403
- function updateFragment(fragment) {
10404
- const layerOption = { layer: up.layer.get(fragment) };
10405
- if (up.fragment.closest(fragment, navSelector(), layerOption)) {
10406
- const links = up.fragment.subtree(fragment, SELECTOR_LINK, layerOption);
10407
- updateLinks(links, layerOption);
10408
- }
10409
- else {
10410
- updateLinksWithinNavs(fragment, layerOption);
10461
+ function updateFragment(fragment, { layer } = {}) {
10462
+ layer ||= up.layer.get(fragment);
10463
+ let layerLocation = getNormalizedLayerLocation(layer);
10464
+ const navSelector = config.selector('navSelectors');
10465
+ const navLinkSelector = `${navSelector} :is(${SELECTOR_LINK}), ${navSelector}:is(${SELECTOR_LINK})`;
10466
+ const links = up.fragment.all(navLinkSelector, { layer });
10467
+ for (let link of links) {
10468
+ const isCurrent = linkURLs(link).isCurrent(layerLocation);
10469
+ for (let currentClass of config.currentClasses) {
10470
+ link.classList.toggle(currentClass, isCurrent);
10471
+ }
10472
+ e.toggleAttr(link, 'aria-current', 'page', isCurrent);
10411
10473
  }
10412
10474
  }
10413
- function updateLinksWithinNavs(fragment, options) {
10414
- const navs = up.fragment.subtree(fragment, navSelector(), options);
10415
- const links = u.flatMap(navs, nav => e.subtree(nav, SELECTOR_LINK));
10416
- updateLinks(links, options);
10417
- }
10418
10475
  function getNormalizedLayerLocation(layer) {
10419
10476
  return layer.feedbackLocation || normalizeURL(layer.location);
10420
10477
  }
10421
- function updateLinks(links, options = {}) {
10422
- if (!links.length) {
10423
- return;
10424
- }
10425
- const layer = options.layer || up.layer.get(links[0]);
10426
- let layerLocation = getNormalizedLayerLocation(layer);
10427
- if (layerLocation) {
10428
- for (let link of links) {
10429
- const isCurrent = linkURLs(link).isCurrent(layerLocation);
10430
- for (let currentClass of config.currentClasses) {
10431
- link.classList.toggle(currentClass, isCurrent);
10432
- }
10433
- e.toggleAttr(link, 'aria-current', 'page', isCurrent);
10434
- }
10435
- }
10436
- }
10437
10478
  function findActivatableArea(element) {
10438
10479
  return e.ancestor(element, SELECTOR_LINK) || element;
10439
10480
  }
@@ -10461,7 +10502,7 @@ up.feedback = (function () {
10461
10502
  const layerLocation = getNormalizedLayerLocation(layer.location);
10462
10503
  if (!processedLocation || (processedLocation !== layerLocation)) {
10463
10504
  layer.feedbackLocation = layerLocation;
10464
- updateLinksWithinNavs(layer.element, { layer });
10505
+ updateFragment(layer.element, { layer });
10465
10506
  }
10466
10507
  }
10467
10508
  function onBrowserLocationChanged() {
@@ -10496,6 +10537,7 @@ up.radio = (function () {
10496
10537
  const e = up.element;
10497
10538
  const config = new up.Config(() => ({
10498
10539
  hungrySelectors: ['[up-hungry]'],
10540
+ noHungrySelectors: ['[up-hungry=false]'],
10499
10541
  pollInterval: 30000,
10500
10542
  }));
10501
10543
  function hungrySteps(renderOptions) {
@@ -10552,7 +10594,7 @@ up.radio = (function () {
10552
10594
  parser.string('ifLayer', { default: 'front' });
10553
10595
  return options;
10554
10596
  }
10555
- up.compiler('[up-poll]:not([up-poll=false])', function (fragment) {
10597
+ up.attribute('up-poll', function (fragment) {
10556
10598
  up.FragmentPolling.forFragment(fragment).onPollAttributeObserved();
10557
10599
  });
10558
10600
  up.macro('[up-flashes]', function (fragment) {