unpoly-rails 3.5.1 → 3.6.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.5.1'
8
+ version: '3.6.0'
9
9
  };
10
10
 
11
11
 
@@ -396,7 +396,8 @@ up.util = (function () {
396
396
  return value[value.length - 1];
397
397
  }
398
398
  function contains(value, subValue) {
399
- return value.indexOf(subValue) >= 0;
399
+ let indexOf = value.indexOf || Array.prototype.indexOf;
400
+ return indexOf.call(value, subValue) >= 0;
400
401
  }
401
402
  function objectContains(object, subObject) {
402
403
  const reducedValue = pick(object, Object.keys(subObject));
@@ -902,14 +903,7 @@ up.browser = (function () {
902
903
  function canJQuery() {
903
904
  return !!window.jQuery;
904
905
  }
905
- const canEval = u.memoize(function () {
906
- try {
907
- return new Function('return true')();
908
- }
909
- catch {
910
- return false;
911
- }
912
- });
906
+ const canHasSelector = u.memoize(() => CSS.supports('selector(:has(*))'));
913
907
  function popCookie(name) {
914
908
  let value = document.cookie.match(new RegExp(name + "=(\\w+)"))?.[1];
915
909
  if (value) {
@@ -928,9 +922,9 @@ up.browser = (function () {
928
922
  submitForm,
929
923
  canPushState,
930
924
  canJQuery,
931
- canEval,
932
925
  assertConfirmed,
933
926
  popCookie,
927
+ canHasSelector,
934
928
  };
935
929
  })();
936
930
 
@@ -1207,12 +1201,8 @@ up.element = (function () {
1207
1201
  function createBrokenDocumentFromHTML(html) {
1208
1202
  return new DOMParser().parseFromString(html, 'text/html');
1209
1203
  }
1210
- function fixScriptish(scriptish) {
1211
- let clone = document.createElement(scriptish.tagName);
1212
- for (let { name, value } of scriptish.attributes) {
1213
- clone.setAttribute(name, value);
1214
- }
1215
- clone.textContent = scriptish.innerHTML;
1204
+ function fixParserDamage(scriptish) {
1205
+ let clone = createFromHTML(scriptish.outerHTML);
1216
1206
  scriptish.replaceWith(clone);
1217
1207
  }
1218
1208
  function createFromHTML(html) {
@@ -1453,16 +1443,12 @@ up.element = (function () {
1453
1443
  jQuery(element).remove();
1454
1444
  }
1455
1445
  }
1456
- function filteredQuery(parent, includeSelectors, excludeSelectors) {
1457
- let fullIncludeSelector = includeSelectors.join();
1458
- let fullExcludeSelector = excludeSelectors.join();
1459
- let elements = parent.querySelectorAll(fullIncludeSelector);
1460
- let isExcluded = (element) => element.matches(fullExcludeSelector);
1461
- return u.reject(elements, isExcluded);
1462
- }
1463
1446
  function isEmpty(element) {
1464
1447
  return !element.children.length > 0 && !element.innerText.trim();
1465
1448
  }
1449
+ function crossOriginSelector(attr) {
1450
+ return `[${attr}*="//"]:not([${attr}*="//${location.host}/"])`;
1451
+ }
1466
1452
  return {
1467
1453
  subtree,
1468
1454
  contains,
@@ -1486,7 +1472,7 @@ up.element = (function () {
1486
1472
  attrSelector,
1487
1473
  tagName: elementTagName,
1488
1474
  createBrokenDocumentFromHTML,
1489
- fixScriptish,
1475
+ fixParserDamage,
1490
1476
  createFromHTML,
1491
1477
  get root() { return getRoot(); },
1492
1478
  paint,
@@ -1517,8 +1503,8 @@ up.element = (function () {
1517
1503
  setTemporaryAttr,
1518
1504
  cleanJQuery,
1519
1505
  parseSelector,
1520
- filteredQuery,
1521
1506
  isEmpty,
1507
+ crossOriginSelector,
1522
1508
  };
1523
1509
  })();
1524
1510
 
@@ -1630,14 +1616,30 @@ up.Record = class Record {
1630
1616
  /* 17 */
1631
1617
  /***/ (() => {
1632
1618
 
1619
+ const u = up.util;
1633
1620
  up.Config = class Config {
1634
1621
  constructor(blueprintFn = (() => ({}))) {
1635
1622
  this._blueprintFn = blueprintFn;
1636
1623
  this.reset();
1624
+ document.addEventListener('up:framework:reset', () => this.reset());
1637
1625
  }
1638
1626
  reset() {
1639
1627
  Object.assign(this, this._blueprintFn());
1640
1628
  }
1629
+ matches(element, prop) {
1630
+ return element.matches(this.selector(prop));
1631
+ }
1632
+ selector(prop) {
1633
+ let includes = this[prop];
1634
+ let excludes = this['no' + u.upperCaseFirst(prop)];
1635
+ let selector = `:is(${includes.join()})`;
1636
+ if (u.isPresent(excludes))
1637
+ selector += `:not(${excludes.join()})`;
1638
+ return selector;
1639
+ }
1640
+ selectorFn(prop) {
1641
+ return () => this.selector(prop);
1642
+ }
1641
1643
  };
1642
1644
 
1643
1645
 
@@ -2220,6 +2222,7 @@ up.Change.OpenLayer = class OpenLayer extends up.Change.Addition {
2220
2222
  _renderOverlayContent() {
2221
2223
  this._handleHistory();
2222
2224
  this.handleLayerChangeRequests();
2225
+ this.responseDoc.commitElement(this._content);
2223
2226
  this.layer.setContent(this._content);
2224
2227
  this.setReloadAttrs({ newElement: this._content, source: this.options.source });
2225
2228
  this.responseDoc.finalizeElement(this._content);
@@ -2526,8 +2529,9 @@ up.Change.UpdateSteps = class UpdateSteps extends up.Change.Addition {
2526
2529
  up.fragment.markAsDestroying(step.oldElement);
2527
2530
  },
2528
2531
  afterInsert: () => {
2529
- this.responseDoc.finalizeElement(step.newElement);
2530
2532
  this._restoreKeepables(step);
2533
+ this.responseDoc.finalizeElement(step.newElement);
2534
+ this._unmarkKeepables(step);
2531
2535
  up.hello(step.newElement, step);
2532
2536
  this._addToResult(step.newElement);
2533
2537
  },
@@ -2616,6 +2620,8 @@ up.Change.UpdateSteps = class UpdateSteps extends up.Change.Addition {
2616
2620
  if (keepPlan) {
2617
2621
  const keepableClone = keepable.cloneNode(true);
2618
2622
  keepable.insertAdjacentElement('beforebegin', keepableClone);
2623
+ keepable.classList.add('up-keeping');
2624
+ up.script.disableSubtree(keepPlan.newElement);
2619
2625
  let viewports = up.viewport.subtree(keepPlan.oldElement);
2620
2626
  keepPlan.revivers = viewports.map(function (viewport) {
2621
2627
  let cursorProps = up.viewport.copyCursorProps(viewport);
@@ -2641,6 +2647,11 @@ up.Change.UpdateSteps = class UpdateSteps extends up.Change.Addition {
2641
2647
  }
2642
2648
  }
2643
2649
  }
2650
+ _unmarkKeepables(step) {
2651
+ for (let keepPlan of step.keepPlans) {
2652
+ keepPlan.oldElement.classList.remove('up-keeping');
2653
+ }
2654
+ }
2644
2655
  _willChangeElement(element) {
2645
2656
  return u.some(this._steps, (step) => step.oldElement.contains(element));
2646
2657
  }
@@ -3876,7 +3887,7 @@ up.FormValidator = class FormValidator {
3876
3887
  options.failOptions = false;
3877
3888
  options.params = up.Params.merge(options.params, ...u.map(dirtyRenderOptionsList, 'params'));
3878
3889
  options.headers = u.merge(...u.map(dirtyRenderOptionsList, 'headers'));
3879
- options.headers[up.protocol.headerize('validate')] = dirtyNames.join(' ') || ':unknown';
3890
+ this._addValidateHeader(options.headers, dirtyNames);
3880
3891
  options.guardEvent = up.event.build('up:form:validate', {
3881
3892
  fields: dirtyFields,
3882
3893
  log: 'Validating form',
@@ -3901,6 +3912,13 @@ up.FormValidator = class FormValidator {
3901
3912
  this._renderDirtySolutions();
3902
3913
  }
3903
3914
  }
3915
+ _addValidateHeader(headers, names) {
3916
+ let key = up.protocol.headerize('validate');
3917
+ let value = names.join(' ');
3918
+ if (!value || value.length > up.protocol.config.maxHeaderSize)
3919
+ value = ':unknown';
3920
+ headers[key] = value;
3921
+ }
3904
3922
  _buildDataMap(solutions) {
3905
3923
  let dataMap = {};
3906
3924
  for (let solution of solutions) {
@@ -4040,7 +4058,7 @@ up.FragmentFinder = class FragmentFinder {
4040
4058
  }
4041
4059
  }
4042
4060
  _findInRegion() {
4043
- if (this._match === 'region' && this._origin?.isConnected) {
4061
+ if (this._match === 'region' && !up.fragment.containsMainPseudo(this._selector) && this._origin?.isConnected) {
4044
4062
  return this._findClosest() || this._findDescendantInRegion();
4045
4063
  }
4046
4064
  }
@@ -5465,25 +5483,19 @@ up.NonceableCallback = class NonceableCallback {
5465
5483
  return new this(match[3], match[2]);
5466
5484
  }
5467
5485
  toFunction(...argNames) {
5468
- if (up.browser.canEval()) {
5469
- return new Function(...argNames, this.script);
5470
- }
5471
- else if (this.nonce) {
5486
+ if (this.nonce) {
5472
5487
  let callbackThis = this;
5473
5488
  return function (...args) {
5474
5489
  return callbackThis._runAsNoncedFunction(this, argNames, args);
5475
5490
  };
5476
5491
  }
5477
5492
  else {
5478
- return this._cannotRun.bind(this);
5493
+ return new Function(...argNames, this.script);
5479
5494
  }
5480
5495
  }
5481
5496
  toString() {
5482
5497
  return `nonce-${this.nonce} ${this.script}`;
5483
5498
  }
5484
- _cannotRun() {
5485
- throw new Error(`Your Content Security Policy disallows inline JavaScript (${this.script}). See https://unpoly.com/csp for solutions.`);
5486
- }
5487
5499
  _runAsNoncedFunction(thisArg, argNames, args) {
5488
5500
  let wrappedScript = `
5489
5501
  try {
@@ -6808,7 +6820,7 @@ up.Response = class Response extends up.Record {
6808
6820
  return this.header('Content-Type');
6809
6821
  }
6810
6822
  get cspNonces() {
6811
- return up.protocol.cspNoncesFromHeader(this.header('Content-Security-Policy'));
6823
+ return up.protocol.cspNoncesFromHeader(this.header('Content-Security-Policy') || this.header('Content-Security-Policy-Report-Only'));
6812
6824
  }
6813
6825
  get lastModified() {
6814
6826
  let header = this.header('Last-Modified');
@@ -6854,9 +6866,6 @@ up.ResponseDoc = (_a = class ResponseDoc {
6854
6866
  else {
6855
6867
  this._parseContent(content || '', target);
6856
6868
  }
6857
- if (!up.fragment.config.runScripts) {
6858
- this._document.querySelectorAll('script').forEach((e) => e.remove());
6859
- }
6860
6869
  this._cspNonces = cspNonces;
6861
6870
  if (origin) {
6862
6871
  let originSelector = up.fragment.tryToTarget(origin);
@@ -6868,7 +6877,7 @@ up.ResponseDoc = (_a = class ResponseDoc {
6868
6877
  }
6869
6878
  _parseDocument(document) {
6870
6879
  document = this._parse(document, e.createBrokenDocumentFromHTML);
6871
- this._scriptishNeedFix = true;
6880
+ this._isDocumentBroken = true;
6872
6881
  this._useParseResult(document);
6873
6882
  }
6874
6883
  _parseFragment(fragment) {
@@ -6944,12 +6953,7 @@ up.ResponseDoc = (_a = class ResponseDoc {
6944
6953
  });
6945
6954
  }
6946
6955
  commitSteps(steps) {
6947
- return steps.filter((step) => {
6948
- if (this._document.contains(step.newElement)) {
6949
- step.newElement.remove();
6950
- return true;
6951
- }
6952
- });
6956
+ return steps.filter((step) => this.commitElement(step.newElement));
6953
6957
  }
6954
6958
  _trySelectStep(step) {
6955
6959
  if (step.newElement) {
@@ -6976,10 +6980,20 @@ up.ResponseDoc = (_a = class ResponseDoc {
6976
6980
  throw new up.CannotMatch();
6977
6981
  }
6978
6982
  }
6983
+ commitElement(element) {
6984
+ if (this._document.contains(element)) {
6985
+ if (!up.fragment.config.runScripts) {
6986
+ up.script.disableSubtree(element);
6987
+ }
6988
+ element.remove();
6989
+ return true;
6990
+ }
6991
+ }
6979
6992
  finalizeElement(element) {
6980
6993
  up.NonceableCallback.adoptNonces(element, this._cspNonces);
6981
- if (this._scriptishNeedFix) {
6982
- element.querySelectorAll('noscript, script').forEach(e.fixScriptish);
6994
+ if (this._isDocumentBroken) {
6995
+ let brokenElements = e.subtree(element, ':is(noscript,script,audio,video):not(.up-keeping, .up-keeping *)');
6996
+ u.each(brokenElements, e.fixParserDamage);
6983
6997
  }
6984
6998
  }
6985
6999
  },
@@ -7008,8 +7022,8 @@ up.RevealMotion = class RevealMotion {
7008
7022
  this._padding = this._options.padding ?? this._options.revealPadding ?? viewportConfig.revealPadding;
7009
7023
  this._top = this._options.top ?? this._options.revealTop ?? viewportConfig.revealTop;
7010
7024
  this._max = this._options.max ?? this._options.revealMax ?? viewportConfig.revealMax;
7011
- this._topObstructions = viewportConfig.fixedTopSelectors;
7012
- this._bottomObstructions = viewportConfig.fixedBottomSelectors;
7025
+ this._topObstructionSelector = viewportConfig.selector('fixedTopSelectors');
7026
+ this._bottomObstructionSelector = viewportConfig.selector('fixedBottomSelectors');
7013
7027
  }
7014
7028
  start() {
7015
7029
  const viewportRect = this._getViewportRect(this._viewport);
@@ -7061,12 +7075,12 @@ up.RevealMotion = class RevealMotion {
7061
7075
  elementRect.top -= this._padding;
7062
7076
  elementRect.height += 2 * this._padding;
7063
7077
  }
7064
- _selectObstructions(selectors) {
7065
- let elements = up.fragment.all(selectors.join(), { layer: this._obstructionsLayer });
7078
+ _selectObstructions(selector) {
7079
+ let elements = up.fragment.all(selector, { layer: this._obstructionsLayer });
7066
7080
  return u.filter(elements, e.isVisible);
7067
7081
  }
7068
7082
  _substractObstructions(viewportRect) {
7069
- for (let obstruction of this._selectObstructions(this._topObstructions)) {
7083
+ for (let obstruction of this._selectObstructions(this._topObstructionSelector)) {
7070
7084
  let obstructionRect = up.Rect.fromElement(obstruction);
7071
7085
  let diff = obstructionRect.bottom - viewportRect.top;
7072
7086
  if (diff > 0) {
@@ -7074,7 +7088,7 @@ up.RevealMotion = class RevealMotion {
7074
7088
  viewportRect.height -= diff;
7075
7089
  }
7076
7090
  }
7077
- for (let obstruction of this._selectObstructions(this._bottomObstructions)) {
7091
+ for (let obstruction of this._selectObstructions(this._bottomObstructionSelector)) {
7078
7092
  let obstructionRect = up.Rect.fromElement(obstruction);
7079
7093
  let diff = viewportRect.bottom - obstructionRect.top;
7080
7094
  if (diff > 0) {
@@ -7112,10 +7126,12 @@ up.Selector = class Selector {
7112
7126
  }
7113
7127
  let expandedTargets = up.fragment.expandTargets(selector, { ...options, layer: expandTargetLayer });
7114
7128
  this._selectors = expandedTargets.map((target) => {
7115
- target = target.replace(CSS_HAS_SUFFIX_PATTERN, (match, descendantSelector) => {
7116
- this._filters.push(element => element.querySelector(descendantSelector));
7117
- return '';
7118
- });
7129
+ if (!up.browser.canHasSelector()) {
7130
+ target = target.replace(CSS_HAS_SUFFIX_PATTERN, (match, descendantSelector) => {
7131
+ this._filters.push(element => element.querySelector(descendantSelector));
7132
+ return '';
7133
+ });
7134
+ }
7119
7135
  return target || '*';
7120
7136
  });
7121
7137
  this._unionSelector = this._selectors.join() || 'match-none';
@@ -7605,6 +7621,7 @@ up.protocol = (function () {
7605
7621
  csrfToken() { return e.metaContent('csrf-token'); },
7606
7622
  cspNonce() { return e.metaContent('csp-nonce'); },
7607
7623
  csrfHeader: 'X-CSRF-Token',
7624
+ maxHeaderSize: 2048,
7608
7625
  }));
7609
7626
  function csrfHeader() {
7610
7627
  return u.evalOption(config.csrfHeader);
@@ -7638,13 +7655,8 @@ up.protocol = (function () {
7638
7655
  params.add(config.methodParam, method);
7639
7656
  return 'POST';
7640
7657
  }
7641
- function reset() {
7642
- config.reset();
7643
- }
7644
- up.on('up:framework:reset', reset);
7645
7658
  return {
7646
7659
  config,
7647
- reset,
7648
7660
  locationFromXHR,
7649
7661
  titleFromXHR,
7650
7662
  targetFromXHR,
@@ -7675,9 +7687,6 @@ up.protocol = (function () {
7675
7687
  up.log = (function () {
7676
7688
  const u = up.util;
7677
7689
  const config = new up.LogConfig();
7678
- function reset() {
7679
- config.reset();
7680
- }
7681
7690
  function printToStandard(...args) {
7682
7691
  if (config.enabled) {
7683
7692
  printToStream('log', ...args);
@@ -7732,7 +7741,6 @@ up.log = (function () {
7732
7741
  }
7733
7742
  }
7734
7743
  up.on('up:framework:boot', printBanner);
7735
- up.on('up:framework:reset', reset);
7736
7744
  function enable() {
7737
7745
  config.enabled = true;
7738
7746
  }
@@ -7779,6 +7787,12 @@ up.script = (function () {
7779
7787
  'up-on-error',
7780
7788
  'up-on-offline',
7781
7789
  ],
7790
+ scriptSelectors: [
7791
+ 'script'
7792
+ ],
7793
+ noScriptSelectors: [
7794
+ 'script[type="application/ld+json"]'
7795
+ ]
7782
7796
  }));
7783
7797
  const SYSTEM_MACRO_PRIORITIES = {
7784
7798
  '[up-back]': -100,
@@ -7906,7 +7920,7 @@ up.script = (function () {
7906
7920
  };
7907
7921
  }
7908
7922
  function findAssets(head = document.head) {
7909
- return e.filteredQuery(head, config.assetSelectors, config.noAssetSelectors);
7923
+ return head.querySelectorAll(config.selector('assetSelectors'));
7910
7924
  }
7911
7925
  function assertAssetsOK(newAssets, renderOptions) {
7912
7926
  let oldAssets = findAssets();
@@ -7916,10 +7930,16 @@ up.script = (function () {
7916
7930
  up.event.assertEmitted('up:assets:changed', { oldAssets, newAssets, renderOptions });
7917
7931
  }
7918
7932
  }
7933
+ function disableScript(scriptElement) {
7934
+ scriptElement.type = 'up-disabled-script';
7935
+ }
7936
+ function disableScriptsInSubtree(root) {
7937
+ let selector = config.selector('scriptSelectors');
7938
+ u.each(e.subtree(root, selector), disableScript);
7939
+ }
7919
7940
  function reset() {
7920
7941
  registeredCompilers = u.filter(registeredCompilers, 'isDefault');
7921
7942
  registeredMacros = u.filter(registeredMacros, 'isDefault');
7922
- config.reset();
7923
7943
  }
7924
7944
  up.on('up:framework:reset', reset);
7925
7945
  return {
@@ -7932,6 +7952,7 @@ up.script = (function () {
7932
7952
  data: readData,
7933
7953
  findAssets,
7934
7954
  assertAssetsOK,
7955
+ disableSubtree: disableScriptsInSubtree,
7935
7956
  };
7936
7957
  })();
7937
7958
  up.compiler = up.script.compiler;
@@ -7958,6 +7979,7 @@ up.history = (function () {
7958
7979
  'link[rel=canonical]',
7959
7980
  'link[rel=icon]',
7960
7981
  '[up-meta]',
7982
+ 'script[type="application/ld+json"]',
7961
7983
  ],
7962
7984
  noMetaTagSelectors: [
7963
7985
  'meta[http-equiv]',
@@ -7968,7 +7990,6 @@ up.history = (function () {
7968
7990
  let previousLocation;
7969
7991
  let nextPreviousLocation;
7970
7992
  function reset() {
7971
- config.reset();
7972
7993
  previousLocation = undefined;
7973
7994
  nextPreviousLocation = undefined;
7974
7995
  trackCurrentLocation();
@@ -8069,7 +8090,7 @@ up.history = (function () {
8069
8090
  }
8070
8091
  });
8071
8092
  function findMetaTags(head = document.head) {
8072
- return e.filteredQuery(head, config.metaTagSelectors, config.noMetaTagSelectors);
8093
+ return head.querySelectorAll(config.selector('metaTagSelectors'));
8073
8094
  }
8074
8095
  function updateMetaTags(newMetaTags) {
8075
8096
  let oldMetaTags = findMetaTags();
@@ -8163,9 +8184,6 @@ up.fragment = (function () {
8163
8184
  skipResponse: defaultSkipResponse
8164
8185
  }));
8165
8186
  u.delegate(config, ['mainTargets'], () => up.layer.config.any);
8166
- function reset() {
8167
- config.reset();
8168
- }
8169
8187
  function defaultSkipResponse({ response, expiredResponse }) {
8170
8188
  return !response.text || response.text === expiredResponse?.text;
8171
8189
  }
@@ -8426,18 +8444,11 @@ up.fragment = (function () {
8426
8444
  let isGood = (klass) => !u.some(config.badTargetClasses, (badTargetClass) => matchesPattern(badTargetClass, klass));
8427
8445
  return u.filter(element.classList, isGood);
8428
8446
  }
8429
- function modernResolveOrigin(target, { origin } = {}) {
8430
- return target.replace(/:origin\b/, function (match) {
8431
- if (origin) {
8432
- return toTarget(origin);
8433
- }
8434
- else {
8435
- up.fail('Missing { origin } element to resolve "%s" reference (found in %s)', match, target);
8436
- }
8437
- });
8438
- }
8439
- function resolveOrigin(...args) {
8440
- return (up.migrate.resolveOrigin || modernResolveOrigin)(...args);
8447
+ const MAIN_PSEUDO = /:main\b/;
8448
+ const LAYER_PSEUDO = /:layer\b/;
8449
+ const ORIGIN_PSEUDO = /:origin\b/;
8450
+ function containsMainPseudo(target) {
8451
+ return MAIN_PSEUDO.test(target);
8441
8452
  }
8442
8453
  function expandTargets(targets, options = {}) {
8443
8454
  const { layer } = options;
@@ -8447,21 +8458,19 @@ up.fragment = (function () {
8447
8458
  targets = u.copy(u.wrapList(targets));
8448
8459
  const expanded = [];
8449
8460
  while (targets.length) {
8450
- const target = targets.shift();
8451
- if (target === ':main' || target === true) {
8452
- let mode;
8453
- if (layer === 'new') {
8454
- mode = options.mode || up.fail('Must pass a { mode } option together with { layer: "new" }');
8455
- }
8456
- else {
8457
- mode = layer.mode;
8458
- }
8459
- targets.unshift(...up.layer.mainTargets(mode));
8460
- }
8461
- else if (target === ':layer') {
8462
- if (layer !== 'new' && !layer.opening) {
8463
- targets.unshift(layer.getFirstSwappableElement());
8464
- }
8461
+ let target = targets.shift();
8462
+ if (target === true)
8463
+ target = ':main';
8464
+ if (containsMainPseudo(target)) {
8465
+ let mode = resolveMode(options);
8466
+ let replaced = up.layer.mainTargets(mode).map((mainTarget) => target.replace(MAIN_PSEUDO, mainTarget));
8467
+ targets.unshift(...replaced);
8468
+ }
8469
+ else if (LAYER_PSEUDO.test(target)) {
8470
+ if (layer === 'new' || layer.opening)
8471
+ continue;
8472
+ let firstSwappableTarget = toTarget(layer.getFirstSwappableElement(), options);
8473
+ targets.unshift(target.replace(LAYER_PSEUDO, firstSwappableTarget));
8465
8474
  }
8466
8475
  else if (u.isElementish(target)) {
8467
8476
  expanded.push(toTarget(target, options));
@@ -8469,11 +8478,30 @@ up.fragment = (function () {
8469
8478
  else if (u.isString(target)) {
8470
8479
  expanded.push(resolveOrigin(target, options));
8471
8480
  }
8472
- else {
8473
- }
8474
8481
  }
8475
8482
  return u.uniq(expanded);
8476
8483
  }
8484
+ function resolveMode({ layer, mode }) {
8485
+ if (layer === 'new') {
8486
+ return mode || up.fail('Must pass a { mode } option together with { layer: "new" }');
8487
+ }
8488
+ else {
8489
+ return layer.mode;
8490
+ }
8491
+ }
8492
+ function modernResolveOrigin(target, { origin } = {}) {
8493
+ return target.replace(ORIGIN_PSEUDO, function (match) {
8494
+ if (origin) {
8495
+ return toTarget(origin);
8496
+ }
8497
+ else {
8498
+ up.fail('Missing { origin } element to resolve "%s" reference (found in %s)', match, target);
8499
+ }
8500
+ });
8501
+ }
8502
+ function resolveOrigin(...args) {
8503
+ return (up.migrate.resolveOrigin || modernResolveOrigin)(...args);
8504
+ }
8477
8505
  function splitTarget(target) {
8478
8506
  return u.parseTokens(target, { separator: 'comma' });
8479
8507
  }
@@ -8584,7 +8612,6 @@ up.fragment = (function () {
8584
8612
  return up.warn('Cannot push history changes. Next fragment update will load in a new page.');
8585
8613
  }
8586
8614
  });
8587
- up.on('up:framework:reset', reset);
8588
8615
  return {
8589
8616
  config,
8590
8617
  reload,
@@ -8623,6 +8650,7 @@ up.fragment = (function () {
8623
8650
  isNotDestroying,
8624
8651
  targetForSteps,
8625
8652
  compressNestedSteps,
8653
+ containsMainPseudo,
8626
8654
  };
8627
8655
  })();
8628
8656
  up.reload = up.fragment.reload;
@@ -8662,13 +8690,7 @@ up.viewport = (function () {
8662
8690
  revealMax() { return 0.5 * window.innerHeight; },
8663
8691
  }));
8664
8692
  const bodyShifter = new up.BodyShifter();
8665
- function reset() {
8666
- config.reset();
8667
- }
8668
- function fullAnchoredRightSelector() {
8669
- return config.anchoredRightSelectors.join();
8670
- }
8671
- up.compiler(fullAnchoredRightSelector, function (element) {
8693
+ up.compiler(config.selectorFn('anchoredRightSelectors'), function (element) {
8672
8694
  return bodyShifter.onAnchoredElementInserted(element);
8673
8695
  });
8674
8696
  function reveal(element, options) {
@@ -8934,7 +8956,6 @@ up.viewport = (function () {
8934
8956
  });
8935
8957
  });
8936
8958
  up.on(window, 'hashchange', () => revealHash());
8937
- up.on('up:framework:reset', reset);
8938
8959
  return {
8939
8960
  reveal,
8940
8961
  revealHash,
@@ -8999,7 +9020,6 @@ up.motion = (function () {
8999
9020
  motionController.reset();
9000
9021
  namedAnimations = pickDefault(namedAnimations);
9001
9022
  namedTransitions = pickDefault(namedTransitions);
9002
- config.reset();
9003
9023
  }
9004
9024
  function isEnabled() {
9005
9025
  return config.enabled;
@@ -9274,7 +9294,6 @@ up.network = (function () {
9274
9294
  function reset() {
9275
9295
  abortRequests();
9276
9296
  queue.reset();
9277
- config.reset();
9278
9297
  cache.reset();
9279
9298
  progressBar?.destroy();
9280
9299
  progressBar = null;
@@ -9543,7 +9562,6 @@ up.layer = (function () {
9543
9562
  return e.callbackAttr(link, attr, { exposedKeys: ['layer', 'value', 'response'] });
9544
9563
  }
9545
9564
  function reset() {
9546
- config.reset();
9547
9565
  stack.reset();
9548
9566
  handlers = u.filter(handlers, 'isDefault');
9549
9567
  }
@@ -9578,7 +9596,7 @@ up.layer = (function () {
9578
9596
  }
9579
9597
  }
9580
9598
  function isWithinForeignOverlay(element) {
9581
- let selector = config.foreignOverlaySelectors.join();
9599
+ let selector = config.selector('foreignOverlaySelectors');
9582
9600
  return !!(selector && element.closest(selector));
9583
9601
  }
9584
9602
  up.on('up:fragment:destroyed', function () {
@@ -9663,7 +9681,7 @@ up.link = (function () {
9663
9681
  }
9664
9682
  const config = new up.Config(() => ({
9665
9683
  followSelectors: combineFollowableSelectors(LINKS_WITH_REMOTE_HTML, ATTRIBUTES_SUGGESTING_FOLLOW).concat(LINKS_WITH_LOCAL_HTML),
9666
- noFollowSelectors: ['[up-follow=false]', 'a[download]', 'a[target]', 'a[href^="#"]:not([up-content]):not([up-fragment]):not([up-document])', 'a[href^="javascript:"]'],
9684
+ noFollowSelectors: ['[up-follow=false]', 'a[download]', 'a[target]', 'a[href^="#"]:not([up-content]):not([up-fragment]):not([up-document])', 'a[href^="javascript:"]', 'a[href^="mailto:"]', e.crossOriginSelector('href'), e.crossOriginSelector('up-href')],
9667
9685
  instantSelectors: ['[up-instant]'],
9668
9686
  noInstantSelectors: ['[up-instant=false]', '[onclick]'],
9669
9687
  preloadSelectors: combineFollowableSelectors(LINKS_WITH_REMOTE_HTML, ['[up-preload]']),
@@ -9671,26 +9689,8 @@ up.link = (function () {
9671
9689
  clickableSelectors: LINKS_WITH_LOCAL_HTML.concat(['[up-emit]', '[up-accept]', '[up-dismiss]', '[up-clickable]']),
9672
9690
  preloadDelay: 90,
9673
9691
  }));
9674
- function fullFollowSelector() {
9675
- return config.followSelectors.join();
9676
- }
9677
- function fullPreloadSelector() {
9678
- return config.preloadSelectors.join();
9679
- }
9680
- function fullInstantSelector() {
9681
- return config.instantSelectors.join();
9682
- }
9683
- function fullClickableSelector() {
9684
- return config.clickableSelectors.join();
9685
- }
9686
- function isFollowDisabled(link) {
9687
- return link.matches(config.noFollowSelectors.join()) || u.isCrossOrigin(link);
9688
- }
9689
9692
  function isPreloadDisabled(link) {
9690
- return !up.browser.canPushState() ||
9691
- link.matches(config.noPreloadSelectors.join()) ||
9692
- isFollowDisabled(link) ||
9693
- !willCache(link);
9693
+ return !up.browser.canPushState() || !isFollowable(link) || !willCache(link);
9694
9694
  }
9695
9695
  function willCache(link) {
9696
9696
  const options = parseRequestOptions(link);
@@ -9703,12 +9703,8 @@ up.link = (function () {
9703
9703
  return request.willCache();
9704
9704
  }
9705
9705
  }
9706
- function isInstantDisabled(link) {
9707
- return link.matches(config.noInstantSelectors.join()) || isFollowDisabled(link);
9708
- }
9709
9706
  function reset() {
9710
9707
  lastMousedownTarget = null;
9711
- config.reset();
9712
9708
  linkPreloader.reset();
9713
9709
  }
9714
9710
  const follow = up.mockable(function (link, options) {
@@ -9823,7 +9819,7 @@ up.link = (function () {
9823
9819
  }
9824
9820
  function isFollowable(link) {
9825
9821
  link = up.fragment.get(link);
9826
- return link.matches(fullFollowSelector()) && !isFollowDisabled(link);
9822
+ return config.matches(link, 'followSelectors');
9827
9823
  }
9828
9824
  function makeFollowable(link) {
9829
9825
  if (!isFollowable(link)) {
@@ -9845,9 +9841,9 @@ up.link = (function () {
9845
9841
  }
9846
9842
  });
9847
9843
  }
9848
- up.macro(fullClickableSelector, makeClickable);
9844
+ up.macro(config.selectorFn('clickableSelectors'), makeClickable);
9849
9845
  function shouldFollowEvent(event, link) {
9850
- if (event.defaultPrevented || isFollowDisabled(link)) {
9846
+ if (event.defaultPrevented) {
9851
9847
  return false;
9852
9848
  }
9853
9849
  const betterTargetSelector = `a, [up-href], ${up.form.fieldSelector()}`;
@@ -9855,9 +9851,12 @@ up.link = (function () {
9855
9851
  return !betterTarget || (betterTarget === link);
9856
9852
  }
9857
9853
  function isInstant(linkOrDescendant) {
9858
- const element = linkOrDescendant.closest(fullInstantSelector());
9854
+ const element = linkOrDescendant.closest(config.selector('instantSelectors'));
9859
9855
  return element && !isInstantDisabled(element);
9860
9856
  }
9857
+ function isInstantDisabled(link) {
9858
+ return config.matches(link, 'noInstantSelectors') || config.matches(link, 'noFollowSelectors');
9859
+ }
9861
9860
  function convertClicks(layer) {
9862
9861
  layer.on('click', function (event, element) {
9863
9862
  if (!up.event.isUnmodified(event)) {
@@ -9893,7 +9892,7 @@ up.link = (function () {
9893
9892
  const method = followMethod(link);
9894
9893
  return up.network.isSafeMethod(method);
9895
9894
  }
9896
- up.on('up:click', fullFollowSelector, function (event, link) {
9895
+ up.on('up:click', config.selectorFn('followSelectors'), function (event, link) {
9897
9896
  if (shouldFollowEvent(event, link)) {
9898
9897
  up.event.halt(event, { log: true });
9899
9898
  up.focus(link, { preventScroll: true });
@@ -9912,7 +9911,7 @@ up.link = (function () {
9912
9911
  makeFollowable(area);
9913
9912
  }
9914
9913
  });
9915
- up.compiler(fullPreloadSelector, function (link) {
9914
+ up.compiler(config.selectorFn('preloadSelectors'), function (link) {
9916
9915
  if (!isPreloadDisabled(link)) {
9917
9916
  linkPreloader.watchLink(link);
9918
9917
  }
@@ -9931,8 +9930,6 @@ up.link = (function () {
9931
9930
  convertClicks,
9932
9931
  config,
9933
9932
  combineFollowableSelectors,
9934
- preloadSelector: fullPreloadSelector,
9935
- followSelector: fullFollowSelector,
9936
9933
  preloadIssue,
9937
9934
  };
9938
9935
  })();
@@ -9960,18 +9957,12 @@ up.form = (function () {
9960
9957
  groupSelectors: ['[up-form-group]', 'fieldset', 'label', 'form'],
9961
9958
  fieldSelectors: ['select', 'input:not([type=submit]):not([type=image])', 'button[type]:not([type=submit])', 'textarea'],
9962
9959
  submitSelectors: up.link.combineFollowableSelectors(['form'], ATTRIBUTES_SUGGESTING_SUBMIT),
9963
- noSubmitSelectors: ['[up-submit=false]', '[target]'],
9960
+ noSubmitSelectors: ['[up-submit=false]', '[target]', e.crossOriginSelector('action')],
9964
9961
  submitButtonSelectors: ['input[type=submit]', 'input[type=image]', 'button[type=submit]', 'button:not([type])'],
9965
9962
  watchInputEvents: ['input', 'change'],
9966
9963
  watchInputDelay: 0,
9967
9964
  watchChangeEvents: ['change'],
9968
9965
  }));
9969
- function fullSubmitSelector() {
9970
- return config.submitSelectors.join();
9971
- }
9972
- function reset() {
9973
- config.reset();
9974
- }
9975
9966
  function fieldSelector(suffix = '') {
9976
9967
  return config.fieldSelectors.map(field => field + suffix).join();
9977
9968
  }
@@ -10003,7 +9994,7 @@ up.form = (function () {
10003
9994
  return e.get(form, selector);
10004
9995
  }
10005
9996
  function submitButtonSelector() {
10006
- return config.submitButtonSelectors.join();
9997
+ return config.selector('submitButtonSelectors');
10007
9998
  }
10008
9999
  const submit = up.mockable((form, options) => {
10009
10000
  return up.render(submitOptions(form, options));
@@ -10281,15 +10272,11 @@ up.form = (function () {
10281
10272
  }
10282
10273
  function isSubmittable(form) {
10283
10274
  form = up.fragment.get(form);
10284
- return form.matches(fullSubmitSelector()) && !isSubmitDisabled(form);
10275
+ return config.matches(form, 'submitSelectors');
10285
10276
  }
10286
- function isSubmitDisabled(form) {
10287
- return form.matches(config.noSubmitSelectors.join());
10288
- }
10289
- up.on('submit', fullSubmitSelector, function (event, form) {
10290
- if (event.defaultPrevented || isSubmitDisabled(form)) {
10277
+ up.on('submit', config.selectorFn('submitSelectors'), function (event, form) {
10278
+ if (event.defaultPrevented)
10291
10279
  return;
10292
- }
10293
10280
  up.event.halt(event, { log: true });
10294
10281
  up.error.muteUncriticalRejection(submit(form));
10295
10282
  });
@@ -10311,7 +10298,6 @@ up.form = (function () {
10311
10298
  });
10312
10299
  up.compiler('[up-watch]', (formOrField) => watch(formOrField));
10313
10300
  up.compiler('[up-autosubmit]', (formOrField) => autosubmit(formOrField));
10314
- up.on('up:framework:reset', reset);
10315
10301
  return {
10316
10302
  config,
10317
10303
  submit,
@@ -10354,14 +10340,13 @@ up.feedback = (function () {
10354
10340
  navSelectors: ['[up-nav]', 'nav'],
10355
10341
  }));
10356
10342
  function reset() {
10357
- config.reset();
10358
10343
  up.layer.root.feedbackLocation = null;
10359
10344
  }
10360
10345
  const CLASS_ACTIVE = 'up-active';
10361
10346
  const CLASS_LOADING = 'up-loading';
10362
10347
  const SELECTOR_LINK = 'a, [up-href]';
10363
10348
  function navSelector() {
10364
- return config.navSelectors.join();
10349
+ return config.selector('navSelectors');
10365
10350
  }
10366
10351
  function normalizeURL(url) {
10367
10352
  if (url) {
@@ -10469,15 +10454,12 @@ up.radio = (function () {
10469
10454
  hungrySelectors: ['[up-hungry]'],
10470
10455
  pollInterval: 30000,
10471
10456
  }));
10472
- function reset() {
10473
- config.reset();
10474
- }
10475
10457
  function hungrySteps(renderOptions) {
10476
10458
  let { useHungry, origin, layer: renderLayer } = renderOptions;
10477
10459
  let steps = { current: [], other: [] };
10478
10460
  if (!useHungry)
10479
10461
  return steps;
10480
- let hungrySelector = config.hungrySelectors.join();
10462
+ let hungrySelector = config.selector('hungrySelectors');
10481
10463
  const layerPreference = [renderLayer, ...renderLayer.ancestors, ...renderLayer.descendants];
10482
10464
  for (let elementLayer of layerPreference) {
10483
10465
  let hungries = up.fragment.all(elementLayer.element, hungrySelector, { layer: elementLayer });
@@ -10541,7 +10523,6 @@ up.radio = (function () {
10541
10523
  event.preventDefault();
10542
10524
  });
10543
10525
  });
10544
- up.on('up:framework:reset', reset);
10545
10526
  return {
10546
10527
  config,
10547
10528
  hungrySteps,