var htmx = (function() { 'use strict' // Public API //* * @type {import("./htmx").HtmxApi} */ const htmx = { /* Event processing */ onLoad: onLoadHelper, process: processNode, on: addEventListenerImpl, off: removeEventListenerImpl, trigger: triggerEvent, ajax: ajaxHelper, /* DOM querying helpers */ find, findAll, closest, values: function(elt, type) { const inputValues = getInputValues(elt, type || 'post') return inputValues.values }, /* DOM manipulation helpers */ remove: removeElement, addClass: addClassToElement, removeClass: removeClassFromElement, toggleClass: toggleClassOnElement, takeClass: takeClassForElement, swap, /* Extension entrypoints */ defineExtension, removeExtension, /* Debugging */ logAll, logNone, logger: null, config: { historyEnabled: true, historyCacheSize: 10, refreshOnHistoryMiss: false, defaultSwapStyle: 'innerHTML', defaultSwapDelay: 0, defaultSettleDelay: 20, includeIndicatorStyles: true, indicatorClass: 'htmx-indicator', requestClass: 'htmx-request', addedClass: 'htmx-added', settlingClass: 'htmx-settling', swappingClass: 'htmx-swapping', allowEval: true, allowScriptTags: true, inlineScriptNonce: '', attributesToSettle: ['class', 'style', 'width', 'height'], withCredentials: false, timeout: 0, wsReconnectDelay: 'full-jitter', wsBinaryType: 'blob', disableSelector: '[hx-disable], [data-hx-disable]', scrollBehavior: 'instant', defaultFocusScroll: false, getCacheBusterParam: false, globalViewTransitions: false, methodsThatUseUrlParams: ['get', 'delete'], selfRequestsOnly: true, ignoreTitle: false, scrollIntoViewOnBoost: true, triggerSpecsCache: null, disableInheritance: false, responseHandling: [ { code: '204', swap: false }, { code: '[23]..', swap: true }, { code: '[45]..', swap: false, error: true } ] }, parseInterval, _: internalEval, version: '2.0a' } /** @type {import("./htmx").HtmxInternalApi} */ const internalAPI = { addTriggerHandler, bodyContains, canAccessLocalStorage, findThisElement, filterValues, swap, hasAttribute, getAttributeValue, getClosestAttributeValue, getClosestMatch, getExpressionVars, getHeaders, getInputValues, getInternalData, getSwapSpecification, getTriggerSpecs, getTarget, makeFragment, mergeObjects, makeSettleInfo, oobSwap, querySelectorExt, settleImmediately, shouldCancel, triggerEvent, triggerErrorEvent, withExtensions } const VERBS = ['get', 'post', 'put', 'delete', 'patch'] const VERB_SELECTOR = VERBS.map(function(verb) { return '[hx-' + verb + '], [data-hx-' + verb + ']' }).join(', ') const HEAD_TAG_REGEX = makeTagRegEx('head') //= =================================================================== // Utilities //= =================================================================== /** * @param {string} tag * @param {boolean} global * @returns {RegExp} */ function makeTagRegEx(tag, global = false) { return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`, global ? 'gim' : 'im') } function parseInterval(str) { if (str == undefined) { return undefined } let interval = NaN if (str.slice(-2) == 'ms') { interval = parseFloat(str.slice(0, -2)) } else if (str.slice(-1) == 's') { interval = parseFloat(str.slice(0, -1)) * 1000 } else if (str.slice(-1) == 'm') { interval = parseFloat(str.slice(0, -1)) * 1000 * 60 } else { interval = parseFloat(str) } return isNaN(interval) ? undefined : interval } /** * @param {Element} elt * @param {string} name * @returns {(string | null)} */ function getRawAttribute(elt, name) { return elt.getAttribute && elt.getAttribute(name) } // resolve with both hx and data-hx prefixes function hasAttribute(elt, qualifiedName) { return elt.hasAttribute && (elt.hasAttribute(qualifiedName) || elt.hasAttribute('data-' + qualifiedName)) } /** * * @param {HTMLElement} elt * @param {string} qualifiedName * @returns {(string | null)} */ function getAttributeValue(elt, qualifiedName) { return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, 'data-' + qualifiedName) } /** * @param {HTMLElement} elt * @returns {HTMLElement | ShadowRoot | null} */ function parentElt(elt) { const parent = elt.parentElement if (!parent && elt.parentNode instanceof ShadowRoot) return elt.parentNode return parent } /** * @returns {Document} */ function getDocument() { return document } /** * @returns {Document | ShadowRoot} */ function getRootNode(elt, global) { return elt.getRootNode ? elt.getRootNode({ composed: global }) : getDocument() } /** * @param {HTMLElement} elt * @param {(e:HTMLElement) => boolean} condition * @returns {HTMLElement | null} */ function getClosestMatch(elt, condition) { while (elt && !condition(elt)) { elt = parentElt(elt) } return elt || null } function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName) { const attributeValue = getAttributeValue(ancestor, attributeName) const disinherit = getAttributeValue(ancestor, 'hx-disinherit') var inherit = getAttributeValue(ancestor, 'hx-inherit') if (initialElement !== ancestor) { if (htmx.config.disableInheritance) { if (inherit && (inherit === '*' || inherit.split(' ').indexOf(attributeName) >= 0)) { return attributeValue } else { return null } } if (disinherit && (disinherit === '*' || disinherit.split(' ').indexOf(attributeName) >= 0)) { return 'unset' } } return attributeValue } /** * @param {HTMLElement} elt * @param {string} attributeName * @returns {string | null} */ function getClosestAttributeValue(elt, attributeName) { let closestAttr = null getClosestMatch(elt, function(e) { return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName) }) if (closestAttr !== 'unset') { return closestAttr } } /** * @param {HTMLElement} elt * @param {string} selector * @returns {boolean} */ function matches(elt, selector) { // @ts-ignore: non-standard properties for browser compatibility // noinspection JSUnresolvedVariable const matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector return matchesFunction && matchesFunction.call(elt, selector) } /** * @param {string} str * @returns {string} */ function getStartTag(str) { const tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i const match = tagMatcher.exec(str) if (match) { return match[1].toLowerCase() } else { return '' } } /** * * @param {string} resp * @param {number} depth * @returns {Document} */ function parseHTML(resp) { const parser = new DOMParser() return parser.parseFromString(resp, 'text/html') } function takeChildrenFor(fragment, elt) { while (elt.childNodes.length > 0) { fragment.append(elt.childNodes[0]) } } function duplicateScript(script) { const newScript = getDocument().createElement('script') forEach(script.attributes, function(attr) { newScript.setAttribute(attr.name, attr.value) }) newScript.textContent = script.textContent newScript.async = false if (htmx.config.inlineScriptNonce) { newScript.nonce = htmx.config.inlineScriptNonce } return newScript } function isJavaScriptScriptNode(script) { return script.matches('script') && (script.type === 'text/javascript' || script.type === 'module' || script.type === '') } // we have to make new copies of script tags that we are going to insert because // SOME browsers (not saying who, but it involves an element and an animal) don't // execute scripts created in