diff options
author | Carson Gross <carson@bigsky.software> | 2023-07-14 14:15:31 -0600 |
---|---|---|
committer | Carson Gross <carson@bigsky.software> | 2023-07-14 14:15:31 -0600 |
commit | ac6839e0785a2a38ac8c539ff174381b6e342703 (patch) | |
tree | f0bba32bdb5949f763deae4074e209a64e50c4f6 /www/themes | |
parent | 2edb023f2004fb4240aa6f1de50a48e2b36591be (diff) | |
download | htmx-ac6839e0785a2a38ac8c539ff174381b6e342703.tar.gz htmx-ac6839e0785a2a38ac8c539ff174381b6e342703.zip |
htmx 1.9.3 release prep
Diffstat (limited to 'www/themes')
-rw-r--r-- | www/themes/htmx-theme/static/js/htmx.js | 115 | ||||
-rw-r--r-- | www/themes/htmx-theme/static/js/preload.js | 9 |
2 files changed, 92 insertions, 32 deletions
diff --git a/www/themes/htmx-theme/static/js/htmx.js b/www/themes/htmx-theme/static/js/htmx.js index c7ea3f45..556247b2 100644 --- a/www/themes/htmx-theme/static/js/htmx.js +++ b/www/themes/htmx-theme/static/js/htmx.js @@ -44,6 +44,7 @@ return (function () { defineExtension : defineExtension, removeExtension : removeExtension, logAll : logAll, + logNone : logNone, logger : null, config : { historyEnabled:true, @@ -71,6 +72,7 @@ return (function () { defaultFocusScroll: false, getCacheBusterParam: false, globalViewTransitions: false, + methodsThatUseUrlParams: ["get"], }, parseInterval:parseInterval, _:internalEval, @@ -82,7 +84,7 @@ return (function () { sock.binaryType = htmx.config.wsBinaryType; return sock; }, - version: "1.9.2" + version: "1.9.3" }; /** @type {import("./htmx").HtmxInternalApi} */ @@ -90,9 +92,11 @@ return (function () { addTriggerHandler: addTriggerHandler, bodyContains: bodyContains, canAccessLocalStorage: canAccessLocalStorage, + findThisElement: findThisElement, filterValues: filterValues, hasAttribute: hasAttribute, getAttributeValue: getAttributeValue, + getClosestAttributeValue: getClosestAttributeValue, getClosestMatch: getClosestMatch, getExpressionVars: getExpressionVars, getHeaders: getHeaders, @@ -105,6 +109,7 @@ return (function () { mergeObjects: mergeObjects, makeSettleInfo: makeSettleInfo, oobSwap: oobSwap, + querySelectorExt: querySelectorExt, selectAndSwap: selectAndSwap, settleImmediately: settleImmediately, shouldCancel: shouldCancel, @@ -475,6 +480,10 @@ return (function () { } } + function logNone() { + htmx.logger = null + } + function find(eltOrSelector, selector) { if (selector) { return eltOrSelector.querySelector(selector); @@ -902,6 +911,17 @@ return (function () { return hash; } + function deInitOnHandlers(elt) { + var internalData = getInternalData(elt); + if (internalData.onHandlers) { + for (let i = 0; i < internalData.onHandlers.length; i++) { + const handlerInfo = internalData.onHandlers[i]; + elt.removeEventListener(handlerInfo.name, handlerInfo.handler); + } + delete internalData.onHandlers + } + } + function deInitNode(element) { var internalData = getInternalData(element); if (internalData.timeout) { @@ -920,12 +940,7 @@ return (function () { } }); } - if (internalData.onHandlers) { - for (let i = 0; i < internalData.onHandlers.length; i++) { - const handlerInfo = internalData.onHandlers[i]; - element.removeEventListener(handlerInfo.name, handlerInfo.handler); - } - } + deInitOnHandlers(element); } function cleanUpElement(element) { @@ -950,7 +965,7 @@ return (function () { newElt = eltBeforeNewContent.nextSibling; } getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later - settleInfo.elts = [] // clear existing elements + settleInfo.elts = settleInfo.elts.filter(e => e != target); while(newElt && newElt !== target) { if (newElt.nodeType === Node.ELEMENT_NODE) { settleInfo.elts.push(newElt); @@ -1299,7 +1314,10 @@ return (function () { var nodeData = getInternalData(elt); nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { - if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) { + if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', { + triggerSpec: spec, + target: elt + }))) { handler(elt); } processPolling(elt, handler, spec); @@ -1361,11 +1379,11 @@ return (function () { return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey); } - function maybeFilterEvent(triggerSpec, evt) { + function maybeFilterEvent(triggerSpec, elt, evt) { var eventFilter = triggerSpec.eventFilter; if(eventFilter){ try { - return eventFilter(evt) !== true; + return eventFilter.call(elt, evt) !== true; } catch(e) { triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source}); return true; @@ -1398,7 +1416,7 @@ return (function () { if (explicitCancel || shouldCancel(evt, elt)) { evt.preventDefault(); } - if (maybeFilterEvent(triggerSpec, evt)) { + if (maybeFilterEvent(triggerSpec, elt, evt)) { return; } var eventData = getInternalData(evt); @@ -1650,6 +1668,9 @@ return (function () { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function (event) { if (maybeCloseSSESource(sseSourceElt)) { + return; + } + if (!bodyContains(elt)) { sseEventSource.removeEventListener(sseEventName, sseListener); return; } @@ -1666,7 +1687,7 @@ return (function () { var target = getTarget(elt) var settleInfo = makeSettleInfo(elt); - selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo) + selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo) settleImmediately(settleInfo.tasks) triggerEvent(elt, "htmx:sseMessage", event) }; @@ -1770,7 +1791,7 @@ return (function () { observer.observe(elt); addEventListener(elt, handler, nodeData, triggerSpec); } else if (triggerSpec.trigger === "load") { - if (!maybeFilterEvent(triggerSpec, makeEvent("load", {elt:elt}))) { + if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) { loadImmediately(elt, handler, nodeData, triggerSpec.delay); } } else if (triggerSpec.pollInterval) { @@ -1820,6 +1841,16 @@ return (function () { return document.querySelector("[hx-boost], [data-hx-boost]"); } + function findHxOnWildcardElements(elt) { + if (!document.evaluate) return [] + + let node = null + const elements = [] + const iter = document.evaluate('//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") ]]', elt) + while (node = iter.iterateNext()) elements.push(node) + return elements + } + function findElementsToProcess(elt) { if (elt.querySelectorAll) { var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : ""; @@ -1879,7 +1910,7 @@ return (function () { function processHxOn(elt) { var hxOnValue = getAttributeValue(elt, 'hx-on'); - if (hxOnValue) { + if (hxOnValue && htmx.config.allowEval) { var handlers = {} var lines = hxOnValue.split("\n"); var currentEvent = null; @@ -1903,6 +1934,22 @@ return (function () { } } + function processHxOnWildcard(elt) { + // wipe any previous on handlers so that this function takes precedence + deInitOnHandlers(elt) + + for (const attr of elt.attributes) { + const { name, value } = attr + if (name.startsWith("hx-on:") || name.startsWith("data-hx-on:")) { + let eventName = name.slice(name.indexOf(":") + 1) + // if the eventName starts with a colon, prepend "htmx" for shorthand support + if (eventName.startsWith(":")) eventName = "htmx" + eventName + + addHxOnEventHandler(elt, eventName, value) + } + } + } + function initNode(elt) { if (elt.closest && elt.closest(htmx.config.disableSelector)) { return; @@ -1959,6 +2006,9 @@ return (function () { elt = resolveTarget(elt); initNode(elt); forEach(findElementsToProcess(elt), function(child) { initNode(child) }); + // Because it happens second, the new way of adding onHandlers superseeds the old one + // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored + forEach(findHxOnWildcardElements(elt), processHxOnWildcard); } //==================================================================== @@ -2196,7 +2246,9 @@ return (function () { swapInnerHTML(historyElement, fragment, settleInfo) settleImmediately(settleInfo.tasks); document.title = cached.title; - window.scrollTo(0, cached.scroll); + setTimeout(function () { + window.scrollTo(0, cached.scroll); + }, 0); // next 'tick', so browser has time to render layout currentPathForHistory = path; triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached}); } else { @@ -2925,8 +2977,12 @@ return (function () { var requestAttrValues = getValuesForElement(elt, 'hx-request'); var eltIsBoosted = getInternalData(elt).boosted; + + var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0 + var requestConfig = { boosted: eltIsBoosted, + useUrlParams: useUrlParams, parameters: filteredParameters, unfilteredParameters: allParameters, headers:headers, @@ -2951,6 +3007,7 @@ return (function () { headers = requestConfig.headers; filteredParameters = requestConfig.parameters; errors = requestConfig.errors; + useUrlParams = requestConfig.useUrlParams; if(errors && errors.length > 0){ triggerEvent(elt, 'htmx:validation:halted', requestConfig) @@ -2962,26 +3019,25 @@ return (function () { var splitPath = path.split("#"); var pathNoAnchor = splitPath[0]; var anchor = splitPath[1]; - var finalPathForGet = null; - if (verb === 'get') { - finalPathForGet = pathNoAnchor; + + var finalPath = path + if (useUrlParams) { + finalPath = pathNoAnchor; var values = Object.keys(filteredParameters).length !== 0; if (values) { - if (finalPathForGet.indexOf("?") < 0) { - finalPathForGet += "?"; + if (finalPath.indexOf("?") < 0) { + finalPath += "?"; } else { - finalPathForGet += "&"; + finalPath += "&"; } - finalPathForGet += urlEncode(filteredParameters); + finalPath += urlEncode(filteredParameters); if (anchor) { - finalPathForGet += "#" + anchor; + finalPath += "#" + anchor; } } - xhr.open('GET', finalPathForGet, true); - } else { - xhr.open(verb.toUpperCase(), path, true); } + xhr.open(verb.toUpperCase(), finalPath, true); xhr.overrideMimeType("text/html"); xhr.withCredentials = requestConfig.withCredentials; xhr.timeout = requestConfig.timeout; @@ -3002,7 +3058,7 @@ return (function () { xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, pathInfo: { requestPath: path, - finalRequestPath: finalPathForGet || path, + finalRequestPath: finalPath, anchor: anchor } }; @@ -3077,7 +3133,8 @@ return (function () { }); }); triggerEvent(elt, 'htmx:beforeSend', responseInfo); - xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters)); + var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters) + xhr.send(params); return promise; } diff --git a/www/themes/htmx-theme/static/js/preload.js b/www/themes/htmx-theme/static/js/preload.js index 21e966f8..f68feab5 100644 --- a/www/themes/htmx-theme/static/js/preload.js +++ b/www/themes/htmx-theme/static/js/preload.js @@ -48,9 +48,12 @@ htmx.defineExtension("preload", { // in the future var hxGet = node.getAttribute("hx-get") || node.getAttribute("data-hx-get") if (hxGet) { - htmx.ajax("GET", hxGet, {handler:function(elt, info) { - done(info.xhr.responseText); - }}); + htmx.ajax("GET", hxGet, { + source: node, + handler:function(elt, info) { + done(info.xhr.responseText); + } + }); return; } |