assets/unpoly/unpoly.js in unpoly-rails-3.5.2 vs assets/unpoly/unpoly.js in unpoly-rails-3.6.0

- old
+ new

@@ -3,11 +3,11 @@ /* 0 */, /* 1 */ /***/ (() => { window.up = { - version: '3.5.2' + version: '3.6.0' }; /***/ }), /* 2 */ @@ -394,11 +394,12 @@ } function last(value) { return value[value.length - 1]; } function contains(value, subValue) { - return value.indexOf(subValue) >= 0; + let indexOf = value.indexOf || Array.prototype.indexOf; + return indexOf.call(value, subValue) >= 0; } function objectContains(object, subObject) { const reducedValue = pick(object, Object.keys(subObject)); return isEqual(subObject, reducedValue); } @@ -900,18 +901,11 @@ return up.protocol.initialRequestMethod() === 'GET'; } function canJQuery() { return !!window.jQuery; } - const canEval = u.memoize(function () { - try { - return new Function('return true')(); - } - catch { - return false; - } - }); + const canHasSelector = u.memoize(() => CSS.supports('selector(:has(*))')); function popCookie(name) { let value = document.cookie.match(new RegExp(name + "=(\\w+)"))?.[1]; if (value) { document.cookie = name + '=;Max-Age=0;Path=/'; return value; @@ -926,13 +920,13 @@ } return { submitForm, canPushState, canJQuery, - canEval, assertConfirmed, popCookie, + canHasSelector, }; })(); /***/ }), @@ -1209,13 +1203,10 @@ } function fixParserDamage(scriptish) { let clone = createFromHTML(scriptish.outerHTML); scriptish.replaceWith(clone); } - function disableScript(scriptElement) { - scriptElement.type = 'up-disabled-script'; - } function createFromHTML(html) { const range = document.createRange(); range.setStart(document.body, 0); const fragment = range.createContextualFragment(html.trim()); let elements = fragment.childNodes; @@ -1450,20 +1441,16 @@ function cleanJQuery(element) { if (up.browser.canJQuery()) { jQuery(element).remove(); } } - function filteredQuery(parent, includeSelectors, excludeSelectors) { - let fullIncludeSelector = includeSelectors.join(); - let fullExcludeSelector = excludeSelectors.join(); - let elements = parent.querySelectorAll(fullIncludeSelector); - let isExcluded = (element) => element.matches(fullExcludeSelector); - return u.reject(elements, isExcluded); - } function isEmpty(element) { return !element.children.length > 0 && !element.innerText.trim(); } + function crossOriginSelector(attr) { + return `[${attr}*="//"]:not([${attr}*="//${location.host}/"])`; + } return { subtree, contains, closestAttr, ancestor, @@ -1514,13 +1501,12 @@ toggleAttr, addTemporaryClass, setTemporaryAttr, cleanJQuery, parseSelector, - filteredQuery, isEmpty, - disableScript, + crossOriginSelector, }; })(); /***/ }), @@ -1628,18 +1614,34 @@ /***/ }), /* 17 */ /***/ (() => { +const u = up.util; up.Config = class Config { constructor(blueprintFn = (() => ({}))) { this._blueprintFn = blueprintFn; this.reset(); + document.addEventListener('up:framework:reset', () => this.reset()); } reset() { Object.assign(this, this._blueprintFn()); } + matches(element, prop) { + return element.matches(this.selector(prop)); + } + selector(prop) { + let includes = this[prop]; + let excludes = this['no' + u.upperCaseFirst(prop)]; + let selector = `:is(${includes.join()})`; + if (u.isPresent(excludes)) + selector += `:not(${excludes.join()})`; + return selector; + } + selectorFn(prop) { + return () => this.selector(prop); + } }; /***/ }), /* 18 */ @@ -2218,10 +2220,11 @@ this.layer.setupHandlers(); } _renderOverlayContent() { this._handleHistory(); this.handleLayerChangeRequests(); + this.responseDoc.commitElement(this._content); this.layer.setContent(this._content); this.setReloadAttrs({ newElement: this._content, source: this.options.source }); this.responseDoc.finalizeElement(this._content); this._newOverlayResult = new up.RenderResult({ layer: this.layer, @@ -2616,11 +2619,11 @@ let keepPlan = this._findKeepPlan({ ...step, oldElement: keepable, descendantsOnly: true }); if (keepPlan) { const keepableClone = keepable.cloneNode(true); keepable.insertAdjacentElement('beforebegin', keepableClone); keepable.classList.add('up-keeping'); - u.each(e.subtree(keepPlan.newElement, 'script'), e.disableScript); + up.script.disableSubtree(keepPlan.newElement); let viewports = up.viewport.subtree(keepPlan.oldElement); keepPlan.revivers = viewports.map(function (viewport) { let cursorProps = up.viewport.copyCursorProps(viewport); return () => up.viewport.copyCursorProps(cursorProps, viewport); }); @@ -3882,11 +3885,11 @@ options.origin = this._form; options.focus ??= 'keep'; options.failOptions = false; options.params = up.Params.merge(options.params, ...u.map(dirtyRenderOptionsList, 'params')); options.headers = u.merge(...u.map(dirtyRenderOptionsList, 'headers')); - options.headers[up.protocol.headerize('validate')] = dirtyNames.join(' ') || ':unknown'; + this._addValidateHeader(options.headers, dirtyNames); options.guardEvent = up.event.build('up:form:validate', { fields: dirtyFields, log: 'Validating form', params: options.params }); @@ -3907,10 +3910,17 @@ finally { this._rendering = false; this._renderDirtySolutions(); } } + _addValidateHeader(headers, names) { + let key = up.protocol.headerize('validate'); + let value = names.join(' '); + if (!value || value.length > up.protocol.config.maxHeaderSize) + value = ':unknown'; + headers[key] = value; + } _buildDataMap(solutions) { let dataMap = {}; for (let solution of solutions) { let data = u.pluckKey(solution.renderOptions, 'data'); let keepData = u.pluckKey(solution.renderOptions, 'keepData'); @@ -4046,11 +4056,11 @@ if (this._preferOldElements) { return this._preferOldElements.find((preferOldElement) => this._document.contains(preferOldElement) && up.fragment.matches(preferOldElement, this._selector)); } } _findInRegion() { - if (this._match === 'region' && this._origin?.isConnected) { + if (this._match === 'region' && !up.fragment.containsMainPseudo(this._selector) && this._origin?.isConnected) { return this._findClosest() || this._findDescendantInRegion(); } } _findClosest() { return up.fragment.closest(this._origin, this._selector, this._options); @@ -5471,29 +5481,23 @@ static fromString(string) { let match = string.match(/^(nonce-([^\s]+)\s)?(.*)$/); return new this(match[3], match[2]); } toFunction(...argNames) { - if (up.browser.canEval()) { - return new Function(...argNames, this.script); - } - else if (this.nonce) { + if (this.nonce) { let callbackThis = this; return function (...args) { return callbackThis._runAsNoncedFunction(this, argNames, args); }; } else { - return this._cannotRun.bind(this); + return new Function(...argNames, this.script); } } toString() { return `nonce-${this.nonce} ${this.script}`; } - _cannotRun() { - throw new Error(`Your Content Security Policy disallows inline JavaScript (${this.script}). See https://unpoly.com/csp for solutions.`); - } _runAsNoncedFunction(thisArg, argNames, args) { let wrappedScript = ` try { up.noncedEval.value = (function(${argNames.join()}) { ${this.script} @@ -6814,11 +6818,11 @@ } get contentType() { return this.header('Content-Type'); } get cspNonces() { - return up.protocol.cspNoncesFromHeader(this.header('Content-Security-Policy')); + return up.protocol.cspNoncesFromHeader(this.header('Content-Security-Policy') || this.header('Content-Security-Policy-Report-Only')); } get lastModified() { let header = this.header('Last-Modified'); if (header) { return new Date(header); @@ -6860,13 +6864,10 @@ this._parseFragment(fragment); } else { this._parseContent(content || '', target); } - if (!up.fragment.config.runScripts) { - this._document.querySelectorAll('script').forEach((e) => e.remove()); - } this._cspNonces = cspNonces; if (origin) { let originSelector = up.fragment.tryToTarget(origin); if (originSelector) { this._rediscoveredOrigin = this.select(originSelector); @@ -6950,16 +6951,11 @@ return steps.filter((step) => { return this._trySelectStep(step) || this._cannotMatchStep(step); }); } commitSteps(steps) { - return steps.filter((step) => { - if (this._document.contains(step.newElement)) { - step.newElement.remove(); - return true; - } - }); + return steps.filter((step) => this.commitElement(step.newElement)); } _trySelectStep(step) { if (step.newElement) { return true; } @@ -6982,10 +6978,19 @@ _cannotMatchStep(step) { if (!step.maybe) { throw new up.CannotMatch(); } } + commitElement(element) { + if (this._document.contains(element)) { + if (!up.fragment.config.runScripts) { + up.script.disableSubtree(element); + } + element.remove(); + return true; + } + } finalizeElement(element) { up.NonceableCallback.adoptNonces(element, this._cspNonces); if (this._isDocumentBroken) { let brokenElements = e.subtree(element, ':is(noscript,script,audio,video):not(.up-keeping, .up-keeping *)'); u.each(brokenElements, e.fixParserDamage); @@ -7015,12 +7020,12 @@ const viewportConfig = up.viewport.config; this._snap = this._options.snap ?? this._options.revealSnap ?? viewportConfig.revealSnap; this._padding = this._options.padding ?? this._options.revealPadding ?? viewportConfig.revealPadding; this._top = this._options.top ?? this._options.revealTop ?? viewportConfig.revealTop; this._max = this._options.max ?? this._options.revealMax ?? viewportConfig.revealMax; - this._topObstructions = viewportConfig.fixedTopSelectors; - this._bottomObstructions = viewportConfig.fixedBottomSelectors; + this._topObstructionSelector = viewportConfig.selector('fixedTopSelectors'); + this._bottomObstructionSelector = viewportConfig.selector('fixedBottomSelectors'); } start() { const viewportRect = this._getViewportRect(this._viewport); const elementRect = up.Rect.fromElement(this._element); if (this._max) { @@ -7068,24 +7073,24 @@ } _addPadding(elementRect) { elementRect.top -= this._padding; elementRect.height += 2 * this._padding; } - _selectObstructions(selectors) { - let elements = up.fragment.all(selectors.join(), { layer: this._obstructionsLayer }); + _selectObstructions(selector) { + let elements = up.fragment.all(selector, { layer: this._obstructionsLayer }); return u.filter(elements, e.isVisible); } _substractObstructions(viewportRect) { - for (let obstruction of this._selectObstructions(this._topObstructions)) { + for (let obstruction of this._selectObstructions(this._topObstructionSelector)) { let obstructionRect = up.Rect.fromElement(obstruction); let diff = obstructionRect.bottom - viewportRect.top; if (diff > 0) { viewportRect.top += diff; viewportRect.height -= diff; } } - for (let obstruction of this._selectObstructions(this._bottomObstructions)) { + for (let obstruction of this._selectObstructions(this._bottomObstructionSelector)) { let obstructionRect = up.Rect.fromElement(obstruction); let diff = viewportRect.bottom - obstructionRect.top; if (diff > 0) { viewportRect.height -= diff; } @@ -7119,14 +7124,16 @@ this._filters.push(match => u.some(this._layers, layer => layer.contains(match))); expandTargetLayer = this._layers[0]; } let expandedTargets = up.fragment.expandTargets(selector, { ...options, layer: expandTargetLayer }); this._selectors = expandedTargets.map((target) => { - target = target.replace(CSS_HAS_SUFFIX_PATTERN, (match, descendantSelector) => { - this._filters.push(element => element.querySelector(descendantSelector)); - return ''; - }); + if (!up.browser.canHasSelector()) { + target = target.replace(CSS_HAS_SUFFIX_PATTERN, (match, descendantSelector) => { + this._filters.push(element => element.querySelector(descendantSelector)); + return ''; + }); + } return target || '*'; }); this._unionSelector = this._selectors.join() || 'match-none'; } matches(element) { @@ -7612,10 +7619,11 @@ methodParam: '_method', csrfParam() { return e.metaContent('csrf-param'); }, csrfToken() { return e.metaContent('csrf-token'); }, cspNonce() { return e.metaContent('csp-nonce'); }, csrfHeader: 'X-CSRF-Token', + maxHeaderSize: 2048, })); function csrfHeader() { return u.evalOption(config.csrfHeader); } function csrfParam() { @@ -7645,17 +7653,12 @@ } function wrapMethod(method, params) { params.add(config.methodParam, method); return 'POST'; } - function reset() { - config.reset(); - } - up.on('up:framework:reset', reset); return { config, - reset, locationFromXHR, titleFromXHR, targetFromXHR, methodFromXHR, acceptLayerFromXHR, @@ -7682,13 +7685,10 @@ /***/ (() => { up.log = (function () { const u = up.util; const config = new up.LogConfig(); - function reset() { - config.reset(); - } function printToStandard(...args) { if (config.enabled) { printToStream('log', ...args); } } @@ -7739,11 +7739,10 @@ else { console.log(logo + text); } } up.on('up:framework:boot', printBanner); - up.on('up:framework:reset', reset); function enable() { config.enabled = true; } function disable() { config.enabled = false; @@ -7786,10 +7785,16 @@ 'up-on-rendered', 'up-on-finished', 'up-on-error', 'up-on-offline', ], + scriptSelectors: [ + 'script' + ], + noScriptSelectors: [ + 'script[type="application/ld+json"]' + ] })); const SYSTEM_MACRO_PRIORITIES = { '[up-back]': -100, '[up-content]': -200, '[up-drawer]': -200, @@ -7913,24 +7918,30 @@ ...parsedJSON, ...element.upCompileData, }; } function findAssets(head = document.head) { - return e.filteredQuery(head, config.assetSelectors, config.noAssetSelectors); + return head.querySelectorAll(config.selector('assetSelectors')); } function assertAssetsOK(newAssets, renderOptions) { let oldAssets = findAssets(); let oldHTML = u.map(oldAssets, 'outerHTML').join(); let newHTML = u.map(newAssets, 'outerHTML').join(); if (oldHTML !== newHTML) { up.event.assertEmitted('up:assets:changed', { oldAssets, newAssets, renderOptions }); } } + function disableScript(scriptElement) { + scriptElement.type = 'up-disabled-script'; + } + function disableScriptsInSubtree(root) { + let selector = config.selector('scriptSelectors'); + u.each(e.subtree(root, selector), disableScript); + } function reset() { registeredCompilers = u.filter(registeredCompilers, 'isDefault'); registeredMacros = u.filter(registeredMacros, 'isDefault'); - config.reset(); } up.on('up:framework:reset', reset); return { config, compiler: registerCompiler, @@ -7939,10 +7950,11 @@ hello, clean, data: readData, findAssets, assertAssetsOK, + disableSubtree: disableScriptsInSubtree, }; })(); up.compiler = up.script.compiler; up.destructor = up.script.destructor; up.macro = up.script.macro; @@ -7965,21 +7977,21 @@ 'meta', 'link[rel=alternate]', 'link[rel=canonical]', 'link[rel=icon]', '[up-meta]', + 'script[type="application/ld+json"]', ], noMetaTagSelectors: [ 'meta[http-equiv]', '[up-meta=false]', 'meta[name=csp-nonce]', ], })); let previousLocation; let nextPreviousLocation; function reset() { - config.reset(); previousLocation = undefined; nextPreviousLocation = undefined; trackCurrentLocation(); } const DEFAULT_NORMALIZE_OPTIONS = { hash: true }; @@ -8076,11 +8088,11 @@ else { setTimeout(register, 100); } }); function findMetaTags(head = document.head) { - return e.filteredQuery(head, config.metaTagSelectors, config.noMetaTagSelectors); + return head.querySelectorAll(config.selector('metaTagSelectors')); } function updateMetaTags(newMetaTags) { let oldMetaTags = findMetaTags(); for (let oldMetaTag of oldMetaTags) { oldMetaTag.remove(); @@ -8170,13 +8182,10 @@ autoScroll: ['hash', 'layer-if-main'], autoRevalidate: (response) => response.expired, skipResponse: defaultSkipResponse })); u.delegate(config, ['mainTargets'], () => up.layer.config.any); - function reset() { - config.reset(); - } function defaultSkipResponse({ response, expiredResponse }) { return !response.text || response.text === expiredResponse?.text; } function sourceOf(element, options = {}) { element = getSmart(element, options); @@ -8433,58 +8442,68 @@ } function goodClassesForTarget(element) { let isGood = (klass) => !u.some(config.badTargetClasses, (badTargetClass) => matchesPattern(badTargetClass, klass)); return u.filter(element.classList, isGood); } - function modernResolveOrigin(target, { origin } = {}) { - return target.replace(/:origin\b/, function (match) { - if (origin) { - return toTarget(origin); - } - else { - up.fail('Missing { origin } element to resolve "%s" reference (found in %s)', match, target); - } - }); + const MAIN_PSEUDO = /:main\b/; + const LAYER_PSEUDO = /:layer\b/; + const ORIGIN_PSEUDO = /:origin\b/; + function containsMainPseudo(target) { + return MAIN_PSEUDO.test(target); } - function resolveOrigin(...args) { - return (up.migrate.resolveOrigin || modernResolveOrigin)(...args); - } function expandTargets(targets, options = {}) { const { layer } = options; if (layer !== 'new' && !(layer instanceof up.Layer)) { up.fail('Must pass an up.Layer as { layer } option, but got %o', layer); } targets = u.copy(u.wrapList(targets)); const expanded = []; while (targets.length) { - const target = targets.shift(); - if (target === ':main' || target === true) { - let mode; - if (layer === 'new') { - mode = options.mode || up.fail('Must pass a { mode } option together with { layer: "new" }'); - } - else { - mode = layer.mode; - } - targets.unshift(...up.layer.mainTargets(mode)); + let target = targets.shift(); + if (target === true) + target = ':main'; + if (containsMainPseudo(target)) { + let mode = resolveMode(options); + let replaced = up.layer.mainTargets(mode).map((mainTarget) => target.replace(MAIN_PSEUDO, mainTarget)); + targets.unshift(...replaced); } - else if (target === ':layer') { - if (layer !== 'new' && !layer.opening) { - targets.unshift(layer.getFirstSwappableElement()); - } + else if (LAYER_PSEUDO.test(target)) { + if (layer === 'new' || layer.opening) + continue; + let firstSwappableTarget = toTarget(layer.getFirstSwappableElement(), options); + targets.unshift(target.replace(LAYER_PSEUDO, firstSwappableTarget)); } else if (u.isElementish(target)) { expanded.push(toTarget(target, options)); } else if (u.isString(target)) { expanded.push(resolveOrigin(target, options)); } - else { - } } return u.uniq(expanded); } + function resolveMode({ layer, mode }) { + if (layer === 'new') { + return mode || up.fail('Must pass a { mode } option together with { layer: "new" }'); + } + else { + return layer.mode; + } + } + function modernResolveOrigin(target, { origin } = {}) { + return target.replace(ORIGIN_PSEUDO, function (match) { + if (origin) { + return toTarget(origin); + } + else { + up.fail('Missing { origin } element to resolve "%s" reference (found in %s)', match, target); + } + }); + } + function resolveOrigin(...args) { + return (up.migrate.resolveOrigin || modernResolveOrigin)(...args); + } function splitTarget(target) { return u.parseTokens(target, { separator: 'comma' }); } function parseTargetSteps(target, options = {}) { let defaultPlacement = options.defaultPlacement || 'swap'; @@ -8591,11 +8610,10 @@ up.hello(documentElement); if (!up.browser.canPushState()) { return up.warn('Cannot push history changes. Next fragment update will load in a new page.'); } }); - up.on('up:framework:reset', reset); return { config, reload, destroy, render, @@ -8630,10 +8648,11 @@ parseTargetSteps, isAlive, isNotDestroying, targetForSteps, compressNestedSteps, + containsMainPseudo, }; })(); up.reload = up.fragment.reload; up.destroy = up.fragment.destroy; up.render = up.fragment.render; @@ -8669,17 +8688,11 @@ revealPadding: 0, revealTop: false, revealMax() { return 0.5 * window.innerHeight; }, })); const bodyShifter = new up.BodyShifter(); - function reset() { - config.reset(); - } - function fullAnchoredRightSelector() { - return config.anchoredRightSelectors.join(); - } - up.compiler(fullAnchoredRightSelector, function (element) { + up.compiler(config.selectorFn('anchoredRightSelectors'), function (element) { return bodyShifter.onAnchoredElementInserted(element); }); function reveal(element, options) { options = u.options(options); element = f.get(element, options); @@ -8941,11 +8954,10 @@ return revealHash(); } }); }); up.on(window, 'hashchange', () => revealHash()); - up.on('up:framework:reset', reset); return { reveal, revealHash, firstHashTarget, config, @@ -9006,11 +9018,10 @@ } function reset() { motionController.reset(); namedAnimations = pickDefault(namedAnimations); namedTransitions = pickDefault(namedTransitions); - config.reset(); } function isEnabled() { return config.enabled; } function animate(element, animation, options) { @@ -9281,11 +9292,10 @@ const cache = new up.Request.Cache(); let progressBar = null; function reset() { abortRequests(); queue.reset(); - config.reset(); cache.reset(); progressBar?.destroy(); progressBar = null; } function makeRequest(...args) { @@ -9550,11 +9560,10 @@ } function closeCallbackAttr(link, attr) { return e.callbackAttr(link, attr, { exposedKeys: ['layer', 'value', 'response'] }); } function reset() { - config.reset(); stack.reset(); handlers = u.filter(handlers, 'isDefault'); } async function open(options) { options = u.options(options, { @@ -9585,11 +9594,11 @@ else { return option.toString(); } } function isWithinForeignOverlay(element) { - let selector = config.foreignOverlaySelectors.join(); + let selector = config.selector('foreignOverlaySelectors'); return !!(selector && element.closest(selector)); } up.on('up:fragment:destroyed', function () { stack.sync(); }); @@ -9670,38 +9679,20 @@ function combineFollowableSelectors(elementSelectors, attributeSelectors) { return u.flatMap(elementSelectors, elementSelector => attributeSelectors.map(attrSelector => elementSelector + attrSelector)); } const config = new up.Config(() => ({ followSelectors: combineFollowableSelectors(LINKS_WITH_REMOTE_HTML, ATTRIBUTES_SUGGESTING_FOLLOW).concat(LINKS_WITH_LOCAL_HTML), - noFollowSelectors: ['[up-follow=false]', 'a[download]', 'a[target]', 'a[href^="#"]:not([up-content]):not([up-fragment]):not([up-document])', 'a[href^="javascript:"]'], + 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')], instantSelectors: ['[up-instant]'], noInstantSelectors: ['[up-instant=false]', '[onclick]'], preloadSelectors: combineFollowableSelectors(LINKS_WITH_REMOTE_HTML, ['[up-preload]']), noPreloadSelectors: ['[up-preload=false]'], clickableSelectors: LINKS_WITH_LOCAL_HTML.concat(['[up-emit]', '[up-accept]', '[up-dismiss]', '[up-clickable]']), preloadDelay: 90, })); - function fullFollowSelector() { - return config.followSelectors.join(); - } - function fullPreloadSelector() { - return config.preloadSelectors.join(); - } - function fullInstantSelector() { - return config.instantSelectors.join(); - } - function fullClickableSelector() { - return config.clickableSelectors.join(); - } - function isFollowDisabled(link) { - return link.matches(config.noFollowSelectors.join()) || u.isCrossOrigin(link); - } function isPreloadDisabled(link) { - return !up.browser.canPushState() || - link.matches(config.noPreloadSelectors.join()) || - isFollowDisabled(link) || - !willCache(link); + return !up.browser.canPushState() || !isFollowable(link) || !willCache(link); } function willCache(link) { const options = parseRequestOptions(link); if (options.url) { if (options.cache == null) { @@ -9710,16 +9701,12 @@ options.basic = true; const request = new up.Request(options); return request.willCache(); } } - function isInstantDisabled(link) { - return link.matches(config.noInstantSelectors.join()) || isFollowDisabled(link); - } function reset() { lastMousedownTarget = null; - config.reset(); linkPreloader.reset(); } const follow = up.mockable(function (link, options) { return up.render(followOptions(link, options)); }); @@ -9830,11 +9817,11 @@ return url; } } function isFollowable(link) { link = up.fragment.get(link); - return link.matches(fullFollowSelector()) && !isFollowDisabled(link); + return config.matches(link, 'followSelectors'); } function makeFollowable(link) { if (!isFollowable(link)) { link.setAttribute('up-follow', ''); } @@ -9852,23 +9839,26 @@ if ((event.key === 'Enter') || (event.key === 'Space')) { return forkEventAsUpClick(event); } }); } - up.macro(fullClickableSelector, makeClickable); + up.macro(config.selectorFn('clickableSelectors'), makeClickable); function shouldFollowEvent(event, link) { - if (event.defaultPrevented || isFollowDisabled(link)) { + if (event.defaultPrevented) { return false; } const betterTargetSelector = `a, [up-href], ${up.form.fieldSelector()}`; const betterTarget = event.target.closest(betterTargetSelector); return !betterTarget || (betterTarget === link); } function isInstant(linkOrDescendant) { - const element = linkOrDescendant.closest(fullInstantSelector()); + const element = linkOrDescendant.closest(config.selector('instantSelectors')); return element && !isInstantDisabled(element); } + function isInstantDisabled(link) { + return config.matches(link, 'noInstantSelectors') || config.matches(link, 'noFollowSelectors'); + } function convertClicks(layer) { layer.on('click', function (event, element) { if (!up.event.isUnmodified(event)) { return; } @@ -9900,11 +9890,11 @@ } function isSafe(link) { const method = followMethod(link); return up.network.isSafeMethod(method); } - up.on('up:click', fullFollowSelector, function (event, link) { + up.on('up:click', config.selectorFn('followSelectors'), function (event, link) { if (shouldFollowEvent(event, link)) { up.event.halt(event, { log: true }); up.focus(link, { preventScroll: true }); up.error.muteUncriticalRejection(follow(link)); } @@ -9919,11 +9909,11 @@ const areaClasses = e.upClasses(childLink); area.classList.add(...areaClasses); makeFollowable(area); } }); - up.compiler(fullPreloadSelector, function (link) { + up.compiler(config.selectorFn('preloadSelectors'), function (link) { if (!isPreloadDisabled(link)) { linkPreloader.watchLink(link); } }); up.on('up:framework:reset', reset); @@ -9938,12 +9928,10 @@ shouldFollowEvent, followMethod, convertClicks, config, combineFollowableSelectors, - preloadSelector: fullPreloadSelector, - followSelector: fullFollowSelector, preloadIssue, }; })(); up.follow = up.link.follow; @@ -9967,22 +9955,16 @@ const ATTRIBUTES_SUGGESTING_SUBMIT = ['[up-submit]', '[up-target]', '[up-layer]', '[up-transition]']; const config = new up.Config(() => ({ groupSelectors: ['[up-form-group]', 'fieldset', 'label', 'form'], fieldSelectors: ['select', 'input:not([type=submit]):not([type=image])', 'button[type]:not([type=submit])', 'textarea'], submitSelectors: up.link.combineFollowableSelectors(['form'], ATTRIBUTES_SUGGESTING_SUBMIT), - noSubmitSelectors: ['[up-submit=false]', '[target]'], + noSubmitSelectors: ['[up-submit=false]', '[target]', e.crossOriginSelector('action')], submitButtonSelectors: ['input[type=submit]', 'input[type=image]', 'button[type=submit]', 'button:not([type])'], watchInputEvents: ['input', 'change'], watchInputDelay: 0, watchChangeEvents: ['change'], })); - function fullSubmitSelector() { - return config.submitSelectors.join(); - } - function reset() { - config.reset(); - } function fieldSelector(suffix = '') { return config.fieldSelectors.map(field => field + suffix).join(); } function isField(element) { return element.matches(fieldSelector()); @@ -10010,11 +9992,11 @@ } } return e.get(form, selector); } function submitButtonSelector() { - return config.submitButtonSelectors.join(); + return config.selector('submitButtonSelectors'); } const submit = up.mockable((form, options) => { return up.render(submitOptions(form, options)); }); function submitOptions(form, options, parserOptions) { @@ -10288,19 +10270,15 @@ function focusedField() { return u.presence(document.activeElement, isField); } function isSubmittable(form) { form = up.fragment.get(form); - return form.matches(fullSubmitSelector()) && !isSubmitDisabled(form); + return config.matches(form, 'submitSelectors'); } - function isSubmitDisabled(form) { - return form.matches(config.noSubmitSelectors.join()); - } - up.on('submit', fullSubmitSelector, function (event, form) { - if (event.defaultPrevented || isSubmitDisabled(form)) { + up.on('submit', config.selectorFn('submitSelectors'), function (event, form) { + if (event.defaultPrevented) return; - } up.event.halt(event, { log: true }); up.error.muteUncriticalRejection(submit(form)); }); up.compiler(validatingFieldSelector, function (fieldOrForm) { let validator = up.FormValidator.forElement(fieldOrForm); @@ -10318,11 +10296,10 @@ up.compiler('[up-show-for]:not(.up-switched), [up-hide-for]:not(.up-switched)', (element) => { switchTarget(element); }); up.compiler('[up-watch]', (formOrField) => watch(formOrField)); up.compiler('[up-autosubmit]', (formOrField) => autosubmit(formOrField)); - up.on('up:framework:reset', reset); return { config, submit, submitOptions, destinationOptions, @@ -10361,18 +10338,17 @@ const config = new up.Config(() => ({ currentClasses: ['up-current'], navSelectors: ['[up-nav]', 'nav'], })); function reset() { - config.reset(); up.layer.root.feedbackLocation = null; } const CLASS_ACTIVE = 'up-active'; const CLASS_LOADING = 'up-loading'; const SELECTOR_LINK = 'a, [up-href]'; function navSelector() { - return config.navSelectors.join(); + return config.selector('navSelectors'); } function normalizeURL(url) { if (url) { return u.normalizeURL(url, { trailingSlash: false, hash: false }); } @@ -10476,19 +10452,16 @@ const e = up.element; const config = new up.Config(() => ({ hungrySelectors: ['[up-hungry]'], pollInterval: 30000, })); - function reset() { - config.reset(); - } function hungrySteps(renderOptions) { let { useHungry, origin, layer: renderLayer } = renderOptions; let steps = { current: [], other: [] }; if (!useHungry) return steps; - let hungrySelector = config.hungrySelectors.join(); + let hungrySelector = config.selector('hungrySelectors'); const layerPreference = [renderLayer, ...renderLayer.ancestors, ...renderLayer.descendants]; for (let elementLayer of layerPreference) { let hungries = up.fragment.all(elementLayer.element, hungrySelector, { layer: elementLayer }); for (let element of hungries) { let selector = up.fragment.tryToTarget(element, { origin }); @@ -10548,10 +10521,9 @@ fragment.addEventListener('up:fragment:keep', function (event) { if (!e.isEmpty(event.newFragment)) event.preventDefault(); }); }); - up.on('up:framework:reset', reset); return { config, hungrySteps, startPolling, stopPolling, \ No newline at end of file