unpoly-rails 3.5.1 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,