Browse code

Update htmx lib

Benjamin Roth authored on08/03/2024 10:15:01
Showing1 changed files
... ...
@@ -44,6 +44,7 @@ return (function () {
44 44
             defineExtension : defineExtension,
45 45
             removeExtension : removeExtension,
46 46
             logAll : logAll,
47
+            logNone : logNone,
47 48
             logger : null,
48 49
             config : {
49 50
                 historyEnabled:true,
... ...
@@ -59,6 +60,7 @@ return (function () {
59 60
                 settlingClass:'htmx-settling',
60 61
                 swappingClass:'htmx-swapping',
61 62
                 allowEval:true,
63
+                allowScriptTags:true,
62 64
                 inlineScriptNonce:'',
63 65
                 attributesToSettle:["class", "style", "width", "height"],
64 66
                 withCredentials:false,
... ...
@@ -71,6 +73,11 @@ return (function () {
71 73
                 defaultFocusScroll: false,
72 74
                 getCacheBusterParam: false,
73 75
                 globalViewTransitions: false,
76
+                methodsThatUseUrlParams: ["get"],
77
+                selfRequestsOnly: false,
78
+                ignoreTitle: false,
79
+                scrollIntoViewOnBoost: true,
80
+                triggerSpecsCache: null,
74 81
             },
75 82
             parseInterval:parseInterval,
76 83
             _:internalEval,
... ...
@@ -82,7 +89,7 @@ return (function () {
82 89
                 sock.binaryType = htmx.config.wsBinaryType;
83 90
                 return sock;
84 91
             },
85
-            version: "1.9.2"
92
+            version: "1.9.10"
86 93
         };
87 94
 
88 95
         /** @type {import("./htmx").HtmxInternalApi} */
... ...
@@ -90,9 +97,11 @@ return (function () {
90 97
             addTriggerHandler: addTriggerHandler,
91 98
             bodyContains: bodyContains,
92 99
             canAccessLocalStorage: canAccessLocalStorage,
100
+            findThisElement: findThisElement,
93 101
             filterValues: filterValues,
94 102
             hasAttribute: hasAttribute,
95 103
             getAttributeValue: getAttributeValue,
104
+            getClosestAttributeValue: getClosestAttributeValue,
96 105
             getClosestMatch: getClosestMatch,
97 106
             getExpressionVars: getExpressionVars,
98 107
             getHeaders: getHeaders,
... ...
@@ -105,6 +114,7 @@ return (function () {
105 114
             mergeObjects: mergeObjects,
106 115
             makeSettleInfo: makeSettleInfo,
107 116
             oobSwap: oobSwap,
117
+            querySelectorExt: querySelectorExt,
108 118
             selectAndSwap: selectAndSwap,
109 119
             settleImmediately: settleImmediately,
110 120
             shouldCancel: shouldCancel,
... ...
@@ -118,24 +128,40 @@ return (function () {
118 128
             return "[hx-" + verb + "], [data-hx-" + verb + "]"
119 129
         }).join(", ");
120 130
 
131
+        var HEAD_TAG_REGEX = makeTagRegEx('head'),
132
+            TITLE_TAG_REGEX = makeTagRegEx('title'),
133
+            SVG_TAGS_REGEX = makeTagRegEx('svg', true);
134
+
121 135
         //====================================================================
122 136
         // Utilities
123 137
         //====================================================================
124 138
 
139
+        /**
140
+         * @param {string} tag
141
+         * @param {boolean} global
142
+         * @returns {RegExp}
143
+         */
144
+        function makeTagRegEx(tag, global = false) {
145
+            return new RegExp(`<${tag}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${tag}>`,
146
+                global ? 'gim' : 'im');
147
+        }
148
+
125 149
         function parseInterval(str) {
126 150
             if (str == undefined)  {
127
-                return undefined
151
+                return undefined;
128 152
             }
153
+
154
+            let interval = NaN;
129 155
             if (str.slice(-2) == "ms") {
130
-                return parseFloat(str.slice(0,-2)) || undefined
131
-            }
132
-            if (str.slice(-1) == "s") {
133
-                return (parseFloat(str.slice(0,-1)) * 1000) || undefined
134
-            }
135
-            if (str.slice(-1) == "m") {
136
-                return (parseFloat(str.slice(0,-1)) * 1000 * 60) || undefined
156
+                interval = parseFloat(str.slice(0, -2));
157
+            } else if (str.slice(-1) == "s") {
158
+                interval = parseFloat(str.slice(0, -1)) * 1000;
159
+            } else if (str.slice(-1) == "m") {
160
+                interval = parseFloat(str.slice(0, -1)) * 1000 * 60;
161
+            } else {
162
+                interval = parseFloat(str);
137 163
             }
138
-            return parseFloat(str) || undefined
164
+            return isNaN(interval) ? undefined : interval;
139 165
         }
140 166
 
141 167
         /**
... ...
@@ -222,7 +248,7 @@ return (function () {
222 248
          * @returns {boolean}
223 249
          */
224 250
         function matches(elt, selector) {
225
-            // @ts-ignore: non-standard properties for browser compatability
251
+            // @ts-ignore: non-standard properties for browser compatibility
226 252
             // noinspection JSUnresolvedVariable
227 253
             var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector;
228 254
             return matchesFunction && matchesFunction.call(elt, selector);
... ...
@@ -267,42 +293,46 @@ return (function () {
267 293
         }
268 294
 
269 295
         function aFullPageResponse(resp) {
270
-            return resp.match(/<body/);
296
+            return /<body/.test(resp)
271 297
         }
272 298
 
273 299
         /**
274 300
          *
275
-         * @param {string} resp
301
+         * @param {string} response
276 302
          * @returns {Element}
277 303
          */
278
-        function makeFragment(resp) {
279
-            var partialResponse = !aFullPageResponse(resp);
304
+        function makeFragment(response) {
305
+            var partialResponse = !aFullPageResponse(response);
306
+            var startTag = getStartTag(response);
307
+            var content = response;
308
+            if (startTag === 'head') {
309
+                content = content.replace(HEAD_TAG_REGEX, '');
310
+            }
280 311
             if (htmx.config.useTemplateFragments && partialResponse) {
281
-                var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0);
312
+                var documentFragment = parseHTML("<body><template>" + content + "</template></body>", 0);
282 313
                 // @ts-ignore type mismatch between DocumentFragment and Element.
283
-                // TODO: Are these close enough for htmx to use interchangably?
314
+                // TODO: Are these close enough for htmx to use interchangeably?
284 315
                 return documentFragment.querySelector('template').content;
285
-            } else {
286
-                var startTag = getStartTag(resp);
287
-                switch (startTag) {
288
-                    case "thead":
289
-                    case "tbody":
290
-                    case "tfoot":
291
-                    case "colgroup":
292
-                    case "caption":
293
-                        return parseHTML("<table>" + resp + "</table>", 1);
294
-                    case "col":
295
-                        return parseHTML("<table><colgroup>" + resp + "</colgroup></table>", 2);
296
-                    case "tr":
297
-                        return parseHTML("<table><tbody>" + resp + "</tbody></table>", 2);
298
-                    case "td":
299
-                    case "th":
300
-                        return parseHTML("<table><tbody><tr>" + resp + "</tr></tbody></table>", 3);
301
-                    case "script":
302
-                        return parseHTML("<div>" + resp + "</div>", 1);
303
-                    default:
304
-                        return parseHTML(resp, 0);
305
-                }
316
+            }
317
+            switch (startTag) {
318
+                case "thead":
319
+                case "tbody":
320
+                case "tfoot":
321
+                case "colgroup":
322
+                case "caption":
323
+                    return parseHTML("<table>" + content + "</table>", 1);
324
+                case "col":
325
+                    return parseHTML("<table><colgroup>" + content + "</colgroup></table>", 2);
326
+                case "tr":
327
+                    return parseHTML("<table><tbody>" + content + "</tbody></table>", 2);
328
+                case "td":
329
+                case "th":
330
+                    return parseHTML("<table><tbody><tr>" + content + "</tr></tbody></table>", 3);
331
+                case "script":
332
+                case "style":
333
+                    return parseHTML("<div>" + content + "</div>", 1);
334
+                default:
335
+                    return parseHTML(content, 0);
306 336
             }
307 337
         }
308 338
 
... ...
@@ -386,7 +416,7 @@ return (function () {
386 416
 
387 417
         function bodyContains(elt) {
388 418
             // IE Fix
389
-            if (elt.getRootNode && elt.getRootNode() instanceof ShadowRoot) {
419
+            if (elt.getRootNode && elt.getRootNode() instanceof window.ShadowRoot) {
390 420
                 return getDocument().body.contains(elt.getRootNode().host);
391 421
             } else {
392 422
                 return getDocument().body.contains(elt);
... ...
@@ -440,7 +470,7 @@ return (function () {
440 470
                     path = url.pathname + url.search;
441 471
                 }
442 472
                 // remove trailing slash, unless index page
443
-                if (!path.match('^/$')) {
473
+                if (!(/^\/$/.test(path))) {
444 474
                     path = path.replace(/\/+$/, '');
445 475
                 }
446 476
                 return path;
... ...
@@ -475,6 +505,10 @@ return (function () {
475 505
             }
476 506
         }
477 507
 
508
+        function logNone() {
509
+            htmx.logger = null
510
+        }
511
+
478 512
         function find(eltOrSelector, selector) {
479 513
             if (selector) {
480 514
                 return eltOrSelector.querySelector(selector);
... ...
@@ -562,9 +596,17 @@ return (function () {
562 596
             }
563 597
         }
564 598
 
599
+        function startsWith(str, prefix) {
600
+            return str.substring(0, prefix.length) === prefix
601
+        }
602
+
603
+        function endsWith(str, suffix) {
604
+            return str.substring(str.length - suffix.length) === suffix
605
+        }
606
+
565 607
         function normalizeSelector(selector) {
566 608
             var trimmedSelector = selector.trim();
567
-            if (trimmedSelector.startsWith("<") && trimmedSelector.endsWith("/>")) {
609
+            if (startsWith(trimmedSelector, "<") && endsWith(trimmedSelector, "/>")) {
568 610
                 return trimmedSelector.substring(1, trimmedSelector.length - 2);
569 611
             } else {
570 612
                 return trimmedSelector;
... ...
@@ -576,14 +618,20 @@ return (function () {
576 618
                 return [closest(elt, normalizeSelector(selector.substr(8)))];
577 619
             } else if (selector.indexOf("find ") === 0) {
578 620
                 return [find(elt, normalizeSelector(selector.substr(5)))];
621
+            } else if (selector === "next") {
622
+                return [elt.nextElementSibling]
579 623
             } else if (selector.indexOf("next ") === 0) {
580 624
                 return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))];
625
+            } else if (selector === "previous") {
626
+                return [elt.previousElementSibling]
581 627
             } else if (selector.indexOf("previous ") === 0) {
582 628
                 return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))];
583 629
             } else if (selector === 'document') {
584 630
                 return [document];
585 631
             } else if (selector === 'window') {
586 632
                 return [window];
633
+            } else if (selector === 'body') {
634
+                return [document.body];
587 635
             } else {
588 636
                 return getDocument().querySelectorAll(normalizeSelector(selector));
589 637
             }
... ...
@@ -751,7 +799,7 @@ return (function () {
751 799
          * @returns
752 800
          */
753 801
         function oobSwap(oobValue, oobElement, settleInfo) {
754
-            var selector = "#" + oobElement.id;
802
+            var selector = "#" + getRawAttribute(oobElement, "id");
755 803
             var swapStyle = "outerHTML";
756 804
             if (oobValue === "true") {
757 805
                 // do nothing
... ...
@@ -799,7 +847,7 @@ return (function () {
799 847
             var oobSelects = getClosestAttributeValue(elt, "hx-select-oob");
800 848
             if (oobSelects) {
801 849
                 var oobSelectValues = oobSelects.split(",");
802
-                for (let i = 0; i < oobSelectValues.length; i++) {
850
+                for (var i = 0; i < oobSelectValues.length; i++) {
803 851
                     var oobSelectValue = oobSelectValues[i].split(":", 2);
804 852
                     var id = oobSelectValue[0].trim();
805 853
                     if (id.indexOf("#") === 0) {
... ...
@@ -832,8 +880,9 @@ return (function () {
832 880
 
833 881
         function handleAttributes(parentNode, fragment, settleInfo) {
834 882
             forEach(fragment.querySelectorAll("[id]"), function (newNode) {
835
-                if (newNode.id && newNode.id.length > 0) {
836
-                    var normalizedId = newNode.id.replace("'", "\\'");
883
+                var id = getRawAttribute(newNode, "id")
884
+                if (id && id.length > 0) {
885
+                    var normalizedId = id.replace("'", "\\'");
837 886
                     var normalizedTag = newNode.tagName.replace(':', '\\:');
838 887
                     var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']");
839 888
                     if (oldNode && oldNode !== parentNode) {
... ...
@@ -902,6 +951,17 @@ return (function () {
902 951
             return hash;
903 952
         }
904 953
 
954
+        function deInitOnHandlers(elt) {
955
+            var internalData = getInternalData(elt);
956
+            if (internalData.onHandlers) {
957
+                for (var i = 0; i < internalData.onHandlers.length; i++) {
958
+                    const handlerInfo = internalData.onHandlers[i];
959
+                    elt.removeEventListener(handlerInfo.event, handlerInfo.listener);
960
+                }
961
+                delete internalData.onHandlers
962
+            }
963
+        }
964
+
905 965
         function deInitNode(element) {
906 966
             var internalData = getInternalData(element);
907 967
             if (internalData.timeout) {
... ...
@@ -920,12 +980,8 @@ return (function () {
920 980
                     }
921 981
                 });
922 982
             }
923
-            if (internalData.onHandlers) {
924
-                for (let i = 0; i < internalData.onHandlers.length; i++) {
925
-                    const handlerInfo = internalData.onHandlers[i];
926
-                    element.removeEventListener(handlerInfo.name, handlerInfo.handler);
927
-                }
928
-            }
983
+            deInitOnHandlers(element);
984
+            forEach(Object.keys(internalData), function(key) { delete internalData[key] });
929 985
         }
930 986
 
931 987
         function cleanUpElement(element) {
... ...
@@ -949,8 +1005,7 @@ return (function () {
949 1005
                 } else {
950 1006
                     newElt = eltBeforeNewContent.nextSibling;
951 1007
                 }
952
-                getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later
953
-                settleInfo.elts = [] // clear existing elements
1008
+                settleInfo.elts = settleInfo.elts.filter(function(e) { return e != target });
954 1009
                 while(newElt && newElt !== target) {
955 1010
                     if (newElt.nodeType === Node.ELEMENT_NODE) {
956 1011
                         settleInfo.elts.push(newElt);
... ...
@@ -995,8 +1050,8 @@ return (function () {
995 1050
             }
996 1051
         }
997 1052
 
998
-        function maybeSelectFromResponse(elt, fragment) {
999
-            var selector = getClosestAttributeValue(elt, "hx-select");
1053
+        function maybeSelectFromResponse(elt, fragment, selectOverride) {
1054
+            var selector = selectOverride || getClosestAttributeValue(elt, "hx-select");
1000 1055
             if (selector) {
1001 1056
                 var newFragment = getDocument().createDocumentFragment();
1002 1057
                 forEach(fragment.querySelectorAll(selector), function (node) {
... ...
@@ -1061,21 +1116,20 @@ return (function () {
1061 1116
 
1062 1117
         function findTitle(content) {
1063 1118
             if (content.indexOf('<title') > -1) {
1064
-                var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, '');
1065
-                var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);
1066
-
1119
+                var contentWithSvgsRemoved = content.replace(SVG_TAGS_REGEX, '');
1120
+                var result = contentWithSvgsRemoved.match(TITLE_TAG_REGEX);
1067 1121
                 if (result) {
1068 1122
                     return result[2];
1069 1123
                 }
1070 1124
             }
1071 1125
         }
1072 1126
 
1073
-        function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) {
1127
+        function selectAndSwap(swapStyle, target, elt, responseText, settleInfo, selectOverride) {
1074 1128
             settleInfo.title = findTitle(responseText);
1075 1129
             var fragment = makeFragment(responseText);
1076 1130
             if (fragment) {
1077 1131
                 handleOutOfBandSwaps(elt, fragment, settleInfo);
1078
-                fragment = maybeSelectFromResponse(elt, fragment);
1132
+                fragment = maybeSelectFromResponse(elt, fragment, selectOverride);
1079 1133
                 handlePreservedElements(fragment);
1080 1134
                 return swap(swapStyle, elt, target, fragment, settleInfo);
1081 1135
             }
... ...
@@ -1095,7 +1149,10 @@ return (function () {
1095 1149
                     }
1096 1150
                 }
1097 1151
             } else {
1098
-                triggerEvent(elt, triggerBody, []);
1152
+                var eventNames = triggerBody.split(",")
1153
+                for (var i = 0; i < eventNames.length; i++) {
1154
+                    triggerEvent(elt, eventNames[i].trim(), []);
1155
+                }
1099 1156
             }
1100 1157
         }
1101 1158
 
... ...
@@ -1105,6 +1162,8 @@ return (function () {
1105 1162
         var SYMBOL_CONT = /[_$a-zA-Z0-9]/;
1106 1163
         var STRINGISH_START = ['"', "'", "/"];
1107 1164
         var NOT_WHITESPACE = /[^\s]/;
1165
+        var COMBINED_SELECTOR_START = /[{(]/;
1166
+        var COMBINED_SELECTOR_END = /[})]/;
1108 1167
         function tokenizeString(str) {
1109 1168
             var tokens = [];
1110 1169
             var position = 0;
... ...
@@ -1187,102 +1246,136 @@ return (function () {
1187 1246
 
1188 1247
         function consumeUntil(tokens, match) {
1189 1248
             var result = "";
1190
-            while (tokens.length > 0 && !tokens[0].match(match)) {
1249
+            while (tokens.length > 0 && !match.test(tokens[0])) {
1191 1250
                 result += tokens.shift();
1192 1251
             }
1193 1252
             return result;
1194 1253
         }
1195 1254
 
1255
+        function consumeCSSSelector(tokens) {
1256
+            var result;
1257
+            if (tokens.length > 0 && COMBINED_SELECTOR_START.test(tokens[0])) {
1258
+                tokens.shift();
1259
+                result = consumeUntil(tokens, COMBINED_SELECTOR_END).trim();
1260
+                tokens.shift();
1261
+            } else {
1262
+                result = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1263
+            }
1264
+            return result;
1265
+        }
1266
+
1196 1267
         var INPUT_SELECTOR = 'input, textarea, select';
1197 1268
 
1198 1269
         /**
1199 1270
          * @param {HTMLElement} elt
1271
+         * @param {string} explicitTrigger
1272
+         * @param {cache} cache for trigger specs
1200 1273
          * @returns {import("./htmx").HtmxTriggerSpecification[]}
1201 1274
          */
1202
-        function getTriggerSpecs(elt) {
1203
-            var explicitTrigger = getAttributeValue(elt, 'hx-trigger');
1275
+        function parseAndCacheTrigger(elt, explicitTrigger, cache) {
1204 1276
             var triggerSpecs = [];
1205
-            if (explicitTrigger) {
1206
-                var tokens = tokenizeString(explicitTrigger);
1207
-                do {
1208
-                    consumeUntil(tokens, NOT_WHITESPACE);
1209
-                    var initialLength = tokens.length;
1210
-                    var trigger = consumeUntil(tokens, /[,\[\s]/);
1211
-                    if (trigger !== "") {
1212
-                        if (trigger === "every") {
1213
-                            var every = {trigger: 'every'};
1214
-                            consumeUntil(tokens, NOT_WHITESPACE);
1215
-                            every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/));
1216
-                            consumeUntil(tokens, NOT_WHITESPACE);
1217
-                            var eventFilter = maybeGenerateConditional(elt, tokens, "event");
1218
-                            if (eventFilter) {
1219
-                                every.eventFilter = eventFilter;
1220
-                            }
1221
-                            triggerSpecs.push(every);
1222
-                        } else if (trigger.indexOf("sse:") === 0) {
1223
-                            triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)});
1224
-                        } else {
1225
-                            var triggerSpec = {trigger: trigger};
1226
-                            var eventFilter = maybeGenerateConditional(elt, tokens, "event");
1227
-                            if (eventFilter) {
1228
-                                triggerSpec.eventFilter = eventFilter;
1229
-                            }
1230
-                            while (tokens.length > 0 && tokens[0] !== ",") {
1231
-                                consumeUntil(tokens, NOT_WHITESPACE)
1232
-                                var token = tokens.shift();
1233
-                                if (token === "changed") {
1234
-                                    triggerSpec.changed = true;
1235
-                                } else if (token === "once") {
1236
-                                    triggerSpec.once = true;
1237
-                                } else if (token === "consume") {
1238
-                                    triggerSpec.consume = true;
1239
-                                } else if (token === "delay" && tokens[0] === ":") {
1240
-                                    tokens.shift();
1241
-                                    triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA));
1242
-                                } else if (token === "from" && tokens[0] === ":") {
1243
-                                    tokens.shift();
1277
+            var tokens = tokenizeString(explicitTrigger);
1278
+            do {
1279
+                consumeUntil(tokens, NOT_WHITESPACE);
1280
+                var initialLength = tokens.length;
1281
+                var trigger = consumeUntil(tokens, /[,\[\s]/);
1282
+                if (trigger !== "") {
1283
+                    if (trigger === "every") {
1284
+                        var every = {trigger: 'every'};
1285
+                        consumeUntil(tokens, NOT_WHITESPACE);
1286
+                        every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/));
1287
+                        consumeUntil(tokens, NOT_WHITESPACE);
1288
+                        var eventFilter = maybeGenerateConditional(elt, tokens, "event");
1289
+                        if (eventFilter) {
1290
+                            every.eventFilter = eventFilter;
1291
+                        }
1292
+                        triggerSpecs.push(every);
1293
+                    } else if (trigger.indexOf("sse:") === 0) {
1294
+                        triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)});
1295
+                    } else {
1296
+                        var triggerSpec = {trigger: trigger};
1297
+                        var eventFilter = maybeGenerateConditional(elt, tokens, "event");
1298
+                        if (eventFilter) {
1299
+                            triggerSpec.eventFilter = eventFilter;
1300
+                        }
1301
+                        while (tokens.length > 0 && tokens[0] !== ",") {
1302
+                            consumeUntil(tokens, NOT_WHITESPACE)
1303
+                            var token = tokens.shift();
1304
+                            if (token === "changed") {
1305
+                                triggerSpec.changed = true;
1306
+                            } else if (token === "once") {
1307
+                                triggerSpec.once = true;
1308
+                            } else if (token === "consume") {
1309
+                                triggerSpec.consume = true;
1310
+                            } else if (token === "delay" && tokens[0] === ":") {
1311
+                                tokens.shift();
1312
+                                triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA));
1313
+                            } else if (token === "from" && tokens[0] === ":") {
1314
+                                tokens.shift();
1315
+                                if (COMBINED_SELECTOR_START.test(tokens[0])) {
1316
+                                    var from_arg = consumeCSSSelector(tokens);
1317
+                                } else {
1244 1318
                                     var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1245 1319
                                     if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") {
1246 1320
                                         tokens.shift();
1247
-                                        from_arg +=
1248
-                                            " " +
1249
-                                            consumeUntil(
1250
-                                                tokens,
1251
-                                                WHITESPACE_OR_COMMA
1252
-                                            );
1321
+                                        var selector = consumeCSSSelector(tokens);
1322
+                                        // `next` and `previous` allow a selector-less syntax
1323
+                                        if (selector.length > 0) {
1324
+                                            from_arg += " " + selector;
1325
+                                        }
1253 1326
                                     }
1254
-                                    triggerSpec.from = from_arg;
1255
-                                } else if (token === "target" && tokens[0] === ":") {
1256
-                                    tokens.shift();
1257
-                                    triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1258
-                                } else if (token === "throttle" && tokens[0] === ":") {
1259
-                                    tokens.shift();
1260
-                                    triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA));
1261
-                                } else if (token === "queue" && tokens[0] === ":") {
1262
-                                    tokens.shift();
1263
-                                    triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1264
-                                } else if ((token === "root" || token === "threshold") && tokens[0] === ":") {
1265
-                                    tokens.shift();
1266
-                                    triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1267
-                                } else {
1268
-                                    triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()});
1269 1327
                                 }
1328
+                                triggerSpec.from = from_arg;
1329
+                            } else if (token === "target" && tokens[0] === ":") {
1330
+                                tokens.shift();
1331
+                                triggerSpec.target = consumeCSSSelector(tokens);
1332
+                            } else if (token === "throttle" && tokens[0] === ":") {
1333
+                                tokens.shift();
1334
+                                triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA));
1335
+                            } else if (token === "queue" && tokens[0] === ":") {
1336
+                                tokens.shift();
1337
+                                triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1338
+                            } else if (token === "root" && tokens[0] === ":") {
1339
+                                tokens.shift();
1340
+                                triggerSpec[token] = consumeCSSSelector(tokens);
1341
+                            } else if (token === "threshold" && tokens[0] === ":") {
1342
+                                tokens.shift();
1343
+                                triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1344
+                            } else {
1345
+                                triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()});
1270 1346
                             }
1271
-                            triggerSpecs.push(triggerSpec);
1272 1347
                         }
1348
+                        triggerSpecs.push(triggerSpec);
1273 1349
                     }
1274
-                    if (tokens.length === initialLength) {
1275
-                        triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()});
1276
-                    }
1277
-                    consumeUntil(tokens, NOT_WHITESPACE);
1278
-                } while (tokens[0] === "," && tokens.shift())
1350
+                }
1351
+                if (tokens.length === initialLength) {
1352
+                    triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()});
1353
+                }
1354
+                consumeUntil(tokens, NOT_WHITESPACE);
1355
+            } while (tokens[0] === "," && tokens.shift())
1356
+            if (cache) {
1357
+                cache[explicitTrigger] = triggerSpecs
1358
+            }
1359
+            return triggerSpecs
1360
+        }
1361
+
1362
+        /**
1363
+         * @param {HTMLElement} elt
1364
+         * @returns {import("./htmx").HtmxTriggerSpecification[]}
1365
+         */
1366
+        function getTriggerSpecs(elt) {
1367
+            var explicitTrigger = getAttributeValue(elt, 'hx-trigger');
1368
+            var triggerSpecs = [];
1369
+            if (explicitTrigger) {
1370
+                var cache = htmx.config.triggerSpecsCache
1371
+                triggerSpecs = (cache && cache[explicitTrigger]) || parseAndCacheTrigger(elt, explicitTrigger, cache)
1279 1372
             }
1280 1373
 
1281 1374
             if (triggerSpecs.length > 0) {
1282 1375
                 return triggerSpecs;
1283 1376
             } else if (matches(elt, 'form')) {
1284 1377
                 return [{trigger: 'submit'}];
1285
-            } else if (matches(elt, 'input[type="button"]')){
1378
+            } else if (matches(elt, 'input[type="button"], input[type="submit"]')){
1286 1379
                 return [{trigger: 'click'}];
1287 1380
             } else if (matches(elt, INPUT_SELECTOR)) {
1288 1381
                 return [{trigger: 'change'}];
... ...
@@ -1299,7 +1392,10 @@ return (function () {
1299 1392
             var nodeData = getInternalData(elt);
1300 1393
             nodeData.timeout = setTimeout(function () {
1301 1394
                 if (bodyContains(elt) && nodeData.cancelled !== true) {
1302
-                    if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) {
1395
+                    if (!maybeFilterEvent(spec, elt, makeEvent('hx:poll:trigger', {
1396
+                        triggerSpec: spec,
1397
+                        target: elt
1398
+                    }))) {
1303 1399
                         handler(elt);
1304 1400
                     }
1305 1401
                     processPolling(elt, handler, spec);
... ...
@@ -1319,7 +1415,7 @@ return (function () {
1319 1415
                 var verb, path;
1320 1416
                 if (elt.tagName === "A") {
1321 1417
                     verb = "get";
1322
-                    path = elt.href; // DOM property gives the fully resolved href of a relative link
1418
+                    path = getRawAttribute(elt, 'href')
1323 1419
                 } else {
1324 1420
                     var rawAttribute = getRawAttribute(elt, "method");
1325 1421
                     verb = rawAttribute ? rawAttribute.toLowerCase() : "get";
... ...
@@ -1329,6 +1425,10 @@ return (function () {
1329 1425
                 }
1330 1426
                 triggerSpecs.forEach(function(triggerSpec) {
1331 1427
                     addEventListener(elt, function(elt, evt) {
1428
+                        if (closest(elt, htmx.config.disableSelector)) {
1429
+                            cleanUpElement(elt)
1430
+                            return
1431
+                        }
1332 1432
                         issueAjaxRequest(verb, path, elt, evt)
1333 1433
                     }, nodeData, triggerSpec, true);
1334 1434
                 });
... ...
@@ -1361,11 +1461,11 @@ return (function () {
1361 1461
             return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey);
1362 1462
         }
1363 1463
 
1364
-        function maybeFilterEvent(triggerSpec, evt) {
1464
+        function maybeFilterEvent(triggerSpec, elt, evt) {
1365 1465
             var eventFilter = triggerSpec.eventFilter;
1366 1466
             if(eventFilter){
1367 1467
                 try {
1368
-                    return eventFilter(evt) !== true;
1468
+                    return eventFilter.call(elt, evt) !== true;
1369 1469
                 } catch(e) {
1370 1470
                     triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source});
1371 1471
                     return true;
... ...
@@ -1382,9 +1482,12 @@ return (function () {
1382 1482
             } else {
1383 1483
                 eltsToListenOn = [elt];
1384 1484
             }
1385
-            // store the initial value of the element so we can tell if it changes
1485
+            // store the initial values of the elements, so we can tell if they change
1386 1486
             if (triggerSpec.changed) {
1387
-                elementData.lastValue = elt.value;
1487
+                eltsToListenOn.forEach(function (eltToListenOn) {
1488
+                    var eltToListenOnData = getInternalData(eltToListenOn);
1489
+                    eltToListenOnData.lastValue = eltToListenOn.value;
1490
+                })
1388 1491
             }
1389 1492
             forEach(eltsToListenOn, function (eltToListenOn) {
1390 1493
                 var eventListener = function (evt) {
... ...
@@ -1398,7 +1501,7 @@ return (function () {
1398 1501
                     if (explicitCancel || shouldCancel(evt, elt)) {
1399 1502
                         evt.preventDefault();
1400 1503
                     }
1401
-                    if (maybeFilterEvent(triggerSpec, evt)) {
1504
+                    if (maybeFilterEvent(triggerSpec, elt, evt)) {
1402 1505
                         return;
1403 1506
                     }
1404 1507
                     var eventData = getInternalData(evt);
... ...
@@ -1424,11 +1527,11 @@ return (function () {
1424 1527
                             }
1425 1528
                         }
1426 1529
                         if (triggerSpec.changed) {
1427
-                            if (elementData.lastValue === elt.value) {
1530
+                            var eltToListenOnData = getInternalData(eltToListenOn)
1531
+                            if (eltToListenOnData.lastValue === eltToListenOn.value) {
1428 1532
                                 return;
1429
-                            } else {
1430
-                                elementData.lastValue = elt.value;
1431 1533
                             }
1534
+                            eltToListenOnData.lastValue = eltToListenOn.value
1432 1535
                         }
1433 1536
                         if (elementData.delayed) {
1434 1537
                             clearTimeout(elementData.delayed);
... ...
@@ -1437,14 +1540,14 @@ return (function () {
1437 1540
                             return;
1438 1541
                         }
1439 1542
 
1440
-                        if (triggerSpec.throttle) {
1543
+                        if (triggerSpec.throttle > 0) {
1441 1544
                             if (!elementData.throttle) {
1442 1545
                                 handler(elt, evt);
1443 1546
                                 elementData.throttle = setTimeout(function () {
1444 1547
                                     elementData.throttle = null;
1445 1548
                                 }, triggerSpec.throttle);
1446 1549
                             }
1447
-                        } else if (triggerSpec.delay) {
1550
+                        } else if (triggerSpec.delay > 0) {
1448 1551
                             elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay);
1449 1552
                         } else {
1450 1553
                             triggerEvent(elt, 'htmx:trigger')
... ...
@@ -1650,6 +1753,9 @@ return (function () {
1650 1753
                 var sseEventSource = getInternalData(sseSourceElt).sseEventSource;
1651 1754
                 var sseListener = function (event) {
1652 1755
                     if (maybeCloseSSESource(sseSourceElt)) {
1756
+                        return;
1757
+                    }
1758
+                    if (!bodyContains(elt)) {
1653 1759
                         sseEventSource.removeEventListener(sseEventName, sseListener);
1654 1760
                         return;
1655 1761
                     }
... ...
@@ -1666,7 +1772,7 @@ return (function () {
1666 1772
                     var target = getTarget(elt)
1667 1773
                     var settleInfo = makeSettleInfo(elt);
1668 1774
 
1669
-                    selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo)
1775
+                    selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo)
1670 1776
                     settleImmediately(settleInfo.tasks)
1671 1777
                     triggerEvent(elt, "htmx:sseMessage", event)
1672 1778
                 };
... ...
@@ -1718,7 +1824,7 @@ return (function () {
1718 1824
                     handler(elt);
1719 1825
                 }
1720 1826
             }
1721
-            if (delay) {
1827
+            if (delay > 0) {
1722 1828
                 setTimeout(load, delay);
1723 1829
             } else {
1724 1830
                 load();
... ...
@@ -1735,6 +1841,10 @@ return (function () {
1735 1841
                     nodeData.verb = verb;
1736 1842
                     triggerSpecs.forEach(function(triggerSpec) {
1737 1843
                         addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) {
1844
+                            if (closest(elt, htmx.config.disableSelector)) {
1845
+                                cleanUpElement(elt)
1846
+                                return
1847
+                            }
1738 1848
                             issueAjaxRequest(verb, path, elt, evt)
1739 1849
                         })
1740 1850
                     });
... ...
@@ -1770,10 +1880,10 @@ return (function () {
1770 1880
                 observer.observe(elt);
1771 1881
                 addEventListener(elt, handler, nodeData, triggerSpec);
1772 1882
             } else if (triggerSpec.trigger === "load") {
1773
-                if (!maybeFilterEvent(triggerSpec, makeEvent("load", {elt:elt}))) {
1883
+                if (!maybeFilterEvent(triggerSpec, elt, makeEvent("load", {elt: elt}))) {
1774 1884
                                 loadImmediately(elt, handler, nodeData, triggerSpec.delay);
1775 1885
                             }
1776
-            } else if (triggerSpec.pollInterval) {
1886
+            } else if (triggerSpec.pollInterval > 0) {
1777 1887
                 nodeData.polling = true;
1778 1888
                 processPolling(elt, handler, triggerSpec);
1779 1889
             } else {
... ...
@@ -1782,7 +1892,7 @@ return (function () {
1782 1892
         }
1783 1893
 
1784 1894
         function evalScript(script) {
1785
-            if (script.type === "text/javascript" || script.type === "module" || script.type === "") {
1895
+            if (htmx.config.allowScriptTags && (script.type === "text/javascript" || script.type === "module" || script.type === "") ) {
1786 1896
                 var newScript = getDocument().createElement("script");
1787 1897
                 forEach(script.attributes, function (attr) {
1788 1898
                     newScript.setAttribute(attr.name, attr.value);
... ...
@@ -1816,14 +1926,46 @@ return (function () {
1816 1926
             });
1817 1927
         }
1818 1928
 
1819
-        function hasChanceOfBeingBoosted() {
1820
-            return document.querySelector("[hx-boost], [data-hx-boost]");
1929
+        function shouldProcessHxOn(elt) {
1930
+            var attributes = elt.attributes
1931
+            for (var j = 0; j < attributes.length; j++) {
1932
+                var attrName = attributes[j].name
1933
+                if (startsWith(attrName, "hx-on:") || startsWith(attrName, "data-hx-on:") ||
1934
+                    startsWith(attrName, "hx-on-") || startsWith(attrName, "data-hx-on-")) {
1935
+                    return true
1936
+                }
1937
+            }
1938
+            return false
1939
+        }
1940
+
1941
+        function findHxOnWildcardElements(elt) {
1942
+            var node = null
1943
+            var elements = []
1944
+
1945
+            if (shouldProcessHxOn(elt)) {
1946
+                elements.push(elt)
1947
+            }
1948
+
1949
+            if (document.evaluate) {
1950
+                var iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
1951
+                                                                           ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt)
1952
+                while (node = iter.iterateNext()) elements.push(node)
1953
+            } else {
1954
+                var allElements = elt.getElementsByTagName("*")
1955
+                for (var i = 0; i < allElements.length; i++) {
1956
+                    if (shouldProcessHxOn(allElements[i])) {
1957
+                        elements.push(allElements[i])
1958
+                    }
1959
+                }
1960
+            }
1961
+
1962
+            return elements
1821 1963
         }
1822 1964
 
1823 1965
         function findElementsToProcess(elt) {
1824 1966
             if (elt.querySelectorAll) {
1825
-                var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : "";
1826
-                var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," +
1967
+                var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";
1968
+                var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," +
1827 1969
                     " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");
1828 1970
                 return results;
1829 1971
             } else {
... ...
@@ -1831,31 +1973,45 @@ return (function () {
1831 1973
             }
1832 1974
         }
1833 1975
 
1834
-        function initButtonTracking(form){
1835
-            var maybeSetLastButtonClicked = function(evt){
1836
-                var elt = closest(evt.target, "button, input[type='submit']");
1837
-                if (elt !== null) {
1838
-                    var internalData = getInternalData(form);
1839
-                    internalData.lastButtonClicked = elt;
1840
-                }
1841
-            };
1842
-
1976
+        // Handle submit buttons/inputs that have the form attribute set
1977
+        // see https://developer.mozilla.org/docs/Web/HTML/Element/button
1978
+         function maybeSetLastButtonClicked(evt) {
1979
+            var elt = closest(evt.target, "button, input[type='submit']");
1980
+            var internalData = getRelatedFormData(evt)
1981
+            if (internalData) {
1982
+              internalData.lastButtonClicked = elt;
1983
+            }
1984
+        };
1985
+        function maybeUnsetLastButtonClicked(evt){
1986
+            var internalData = getRelatedFormData(evt)
1987
+            if (internalData) {
1988
+              internalData.lastButtonClicked = null;
1989
+            }
1990
+        }
1991
+        function getRelatedFormData(evt) {
1992
+           var elt = closest(evt.target, "button, input[type='submit']");
1993
+           if (!elt) {
1994
+             return;
1995
+           }
1996
+           var form = resolveTarget('#' + getRawAttribute(elt, 'form')) || closest(elt, 'form');
1997
+           if (!form) {
1998
+             return;
1999
+           }
2000
+           return getInternalData(form);
2001
+        }
2002
+        function initButtonTracking(elt) {
1843 2003
             // need to handle both click and focus in:
1844 2004
             //   focusin - in case someone tabs in to a button and hits the space bar
1845 2005
             //   click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724
1846
-
1847
-            form.addEventListener('click', maybeSetLastButtonClicked)
1848
-            form.addEventListener('focusin', maybeSetLastButtonClicked)
1849
-            form.addEventListener('focusout', function(evt){
1850
-                var internalData = getInternalData(form);
1851
-                internalData.lastButtonClicked = null;
1852
-            })
2006
+            elt.addEventListener('click', maybeSetLastButtonClicked)
2007
+            elt.addEventListener('focusin', maybeSetLastButtonClicked)
2008
+            elt.addEventListener('focusout', maybeUnsetLastButtonClicked)
1853 2009
         }
1854 2010
 
1855 2011
         function countCurlies(line) {
1856 2012
             var tokens = tokenizeString(line);
1857 2013
             var netCurlies = 0;
1858
-            for (let i = 0; i < tokens.length; i++) {
2014
+            for (var i = 0; i < tokens.length; i++) {
1859 2015
                 const token = tokens[i];
1860 2016
                 if (token === "{") {
1861 2017
                     netCurlies++;
... ...
@@ -1868,13 +2024,20 @@ return (function () {
1868 2024
 
1869 2025
         function addHxOnEventHandler(elt, eventName, code) {
1870 2026
             var nodeData = getInternalData(elt);
1871
-            nodeData.onHandlers = [];
1872
-            var func = new Function("event", code + "; return;");
1873
-            var listener = elt.addEventListener(eventName, function (e) {
1874
-                return func.call(elt, e);
1875
-            });
2027
+            if (!Array.isArray(nodeData.onHandlers)) {
2028
+                nodeData.onHandlers = [];
2029
+            }
2030
+            var func;
2031
+            var listener = function (e) {
2032
+                return maybeEval(elt, function() {
2033
+                    if (!func) {
2034
+                        func = new Function("event", code);
2035
+                    }
2036
+                    func.call(elt, e);
2037
+                });
2038
+            };
2039
+            elt.addEventListener(eventName, listener);
1876 2040
             nodeData.onHandlers.push({event:eventName, listener:listener});
1877
-            return {nodeData, code, func, listener};
1878 2041
         }
1879 2042
 
1880 2043
         function processHxOn(elt) {
... ...
@@ -1886,7 +2049,7 @@ return (function () {
1886 2049
                 var curlyCount = 0;
1887 2050
                 while (lines.length > 0) {
1888 2051
                     var line = lines.shift();
1889
-                    var match = line.match(/^\s*([a-zA-Z:\-]+:)(.*)/);
2052
+                    var match = line.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);
1890 2053
                     if (curlyCount === 0 && match) {
1891 2054
                         line.split(":")
1892 2055
                         currentEvent = match[1].slice(0, -1); // strip last colon
... ...
@@ -1903,18 +2066,45 @@ return (function () {
1903 2066
             }
1904 2067
         }
1905 2068
 
2069
+        function processHxOnWildcard(elt) {
2070
+            // wipe any previous on handlers so that this function takes precedence
2071
+            deInitOnHandlers(elt)
2072
+
2073
+            for (var i = 0; i < elt.attributes.length; i++) {
2074
+                var name = elt.attributes[i].name
2075
+                var value = elt.attributes[i].value
2076
+                if (startsWith(name, "hx-on") || startsWith(name, "data-hx-on")) {
2077
+                    var afterOnPosition = name.indexOf("-on") + 3;
2078
+                    var nextChar = name.slice(afterOnPosition, afterOnPosition + 1);
2079
+                    if (nextChar === "-" || nextChar === ":") {
2080
+                        var eventName = name.slice(afterOnPosition + 1);
2081
+                        // if the eventName starts with a colon or dash, prepend "htmx" for shorthand support
2082
+                        if (startsWith(eventName, ":")) {
2083
+                            eventName = "htmx" + eventName
2084
+                        } else if (startsWith(eventName, "-")) {
2085
+                            eventName = "htmx:" + eventName.slice(1);
2086
+                        } else if (startsWith(eventName, "htmx-")) {
2087
+                            eventName = "htmx:" + eventName.slice(5);
2088
+                        }
2089
+
2090
+                        addHxOnEventHandler(elt, eventName, value)
2091
+                    }
2092
+                }
2093
+            }
2094
+        }
2095
+
1906 2096
         function initNode(elt) {
1907
-            if (elt.closest && elt.closest(htmx.config.disableSelector)) {
2097
+            if (closest(elt, htmx.config.disableSelector)) {
2098
+                cleanUpElement(elt)
1908 2099
                 return;
1909 2100
             }
1910 2101
             var nodeData = getInternalData(elt);
1911 2102
             if (nodeData.initHash !== attributeHash(elt)) {
1912
-
1913
-                nodeData.initHash = attributeHash(elt);
1914
-
1915 2103
                 // clean up any previously processed info
1916 2104
                 deInitNode(elt);
1917 2105
 
2106
+                nodeData.initHash = attributeHash(elt);
2107
+
1918 2108
                 processHxOn(elt);
1919 2109
 
1920 2110
                 triggerEvent(elt, "htmx:beforeProcessNode")
... ...
@@ -1938,8 +2128,10 @@ return (function () {
1938 2128
                     }
1939 2129
                 }
1940 2130
 
1941
-                if (elt.tagName === "FORM") {
1942
-                    initButtonTracking(elt);
2131
+                // Handle submit buttons/inputs that have the form attribute set
2132
+                // see https://developer.mozilla.org/docs/Web/HTML/Element/button
2133
+                if (elt.tagName === "FORM" || (getRawAttribute(elt, "type") === "submit" && hasAttribute(elt, "form"))) {
2134
+                    initButtonTracking(elt)
1943 2135
                 }
1944 2136
 
1945 2137
                 var sseInfo = getAttributeValue(elt, 'hx-sse');
... ...
@@ -1957,8 +2149,15 @@ return (function () {
1957 2149
 
1958 2150
         function processNode(elt) {
1959 2151
             elt = resolveTarget(elt);
2152
+            if (closest(elt, htmx.config.disableSelector)) {
2153
+                cleanUpElement(elt)
2154
+                return;
2155
+            }
1960 2156
             initNode(elt);
1961 2157
             forEach(findElementsToProcess(elt), function(child) { initNode(child) });
2158
+            // Because it happens second, the new way of adding onHandlers superseeds the old one
2159
+            // i.e. if there are any hx-on:eventName attributes, the hx-on attribute will be ignored
2160
+            forEach(findHxOnWildcardElements(elt), processHxOnWildcard);
1962 2161
         }
1963 2162
 
1964 2163
         //====================================================================
... ...
@@ -2036,7 +2235,7 @@ return (function () {
2036 2235
                 eventResult = eventResult && elt.dispatchEvent(kebabedEvent)
2037 2236
             }
2038 2237
             withExtensions(elt, function (extension) {
2039
-                eventResult = eventResult && (extension.onEvent(eventName, event) !== false)
2238
+                eventResult = eventResult && (extension.onEvent(eventName, event) !== false && !event.defaultPrevented)
2040 2239
             });
2041 2240
             return eventResult;
2042 2241
         }
... ...
@@ -2056,6 +2255,12 @@ return (function () {
2056 2255
                 return;
2057 2256
             }
2058 2257
 
2258
+            if (htmx.config.historyCacheSize <= 0) {
2259
+                // make sure that an eventually already existing cache is purged
2260
+                localStorage.removeItem("htmx-history-cache");
2261
+                return;
2262
+            }
2263
+
2059 2264
             url = normalizePath(url);
2060 2265
 
2061 2266
             var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || [];
... ...
@@ -2116,7 +2321,13 @@ return (function () {
2116 2321
             // so we can prevent privileged data entering the cache.
2117 2322
             // The page will still be reachable as a history entry, but htmx will fetch it
2118 2323
             // live from the server onpopstate rather than look in the localStorage cache
2119
-            var disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]');
2324
+            var disableHistoryCache
2325
+            try {
2326
+                disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]')
2327
+            } catch (e) {
2328
+                // IE11: insensitive modifier not supported so fallback to case sensitive selector
2329
+                disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]')
2330
+            }
2120 2331
             if (!disableHistoryCache) {
2121 2332
                 triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt});
2122 2333
                 saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY);
... ...
@@ -2129,7 +2340,7 @@ return (function () {
2129 2340
             // remove the cache buster parameter, if any
2130 2341
             if (htmx.config.getCacheBusterParam) {
2131 2342
                 path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '')
2132
-                if (path.endsWith('&') || path.endsWith("?")) {
2343
+                if (endsWith(path, '&') || endsWith(path, "?")) {
2133 2344
                     path = path.slice(0, -1);
2134 2345
                 }
2135 2346
             }
... ...
@@ -2155,7 +2366,9 @@ return (function () {
2155 2366
             var details = {path: path, xhr:request};
2156 2367
             triggerEvent(getDocument().body, "htmx:historyCacheMiss", details);
2157 2368
             request.open('GET', path, true);
2369
+            request.setRequestHeader("HX-Request", "true");
2158 2370
             request.setRequestHeader("HX-History-Restore-Request", "true");
2371
+            request.setRequestHeader("HX-Current-URL", getDocument().location.href);
2159 2372
             request.onload = function () {
2160 2373
                 if (this.status >= 200 && this.status < 400) {
2161 2374
                     triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details);
... ...
@@ -2196,7 +2409,9 @@ return (function () {
2196 2409
                 swapInnerHTML(historyElement, fragment, settleInfo)
2197 2410
                 settleImmediately(settleInfo.tasks);
2198 2411
                 document.title = cached.title;
2199
-                window.scrollTo(0, cached.scroll);
2412
+                setTimeout(function () {
2413
+                    window.scrollTo(0, cached.scroll);
2414
+                }, 0); // next 'tick', so browser has time to render layout
2200 2415
                 currentPathForHistory = path;
2201 2416
                 triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached});
2202 2417
             } else {
... ...
@@ -2223,7 +2438,20 @@ return (function () {
2223 2438
             return indicators;
2224 2439
         }
2225 2440
 
2226
-        function removeRequestIndicatorClasses(indicators) {
2441
+        function disableElements(elt) {
2442
+            var disabledElts = findAttributeTargets(elt, 'hx-disabled-elt');
2443
+            if (disabledElts == null) {
2444
+                disabledElts = [];
2445
+            }
2446
+            forEach(disabledElts, function (disabledElement) {
2447
+                var internalData = getInternalData(disabledElement);
2448
+                internalData.requestCount = (internalData.requestCount || 0) + 1;
2449
+                disabledElement.setAttribute("disabled", "");
2450
+            });
2451
+            return disabledElts;
2452
+        }
2453
+
2454
+        function removeRequestIndicators(indicators, disabled) {
2227 2455
             forEach(indicators, function (ic) {
2228 2456
                 var internalData = getInternalData(ic);
2229 2457
                 internalData.requestCount = (internalData.requestCount || 0) - 1;
... ...
@@ -2231,6 +2459,13 @@ return (function () {
2231 2459
                     ic.classList["remove"].call(ic.classList, htmx.config.requestClass);
2232 2460
                 }
2233 2461
             });
2462
+            forEach(disabled, function (disabledElement) {
2463
+                var internalData = getInternalData(disabledElement);
2464
+                internalData.requestCount = (internalData.requestCount || 0) - 1;
2465
+                if (internalData.requestCount === 0) {
2466
+                    disabledElement.removeAttribute('disabled');
2467
+                }
2468
+            });
2234 2469
         }
2235 2470
 
2236 2471
         //====================================================================
... ...
@@ -2248,7 +2483,7 @@ return (function () {
2248 2483
         }
2249 2484
 
2250 2485
         function shouldInclude(elt) {
2251
-            if(elt.name === "" || elt.name == null || elt.disabled) {
2486
+            if(elt.name === "" || elt.name == null || elt.disabled || closest(elt, "fieldset[disabled]")) {
2252 2487
                 return false;
2253 2488
             }
2254 2489
             // ignore "submitter" types (see jQuery src/serialize.js)
... ...
@@ -2261,6 +2496,29 @@ return (function () {
2261 2496
             return true;
2262 2497
         }
2263 2498
 
2499
+        function addValueToValues(name, value, values) {
2500
+            // This is a little ugly because both the current value of the named value in the form
2501
+            // and the new value could be arrays, so we have to handle all four cases :/
2502
+            if (name != null && value != null) {
2503
+                var current = values[name];
2504
+                if (current === undefined) {
2505
+                    values[name] = value;
2506
+                } else if (Array.isArray(current)) {
2507
+                    if (Array.isArray(value)) {
2508
+                        values[name] = current.concat(value);
2509
+                    } else {
2510
+                        current.push(value);
2511
+                    }
2512
+                } else {
2513
+                    if (Array.isArray(value)) {
2514
+                        values[name] = [current].concat(value);
2515
+                    } else {
2516
+                        values[name] = [current, value];
2517
+                    }
2518
+                }
2519
+            }
2520
+        }
2521
+
2264 2522
         function processInputValue(processed, values, errors, elt, validate) {
2265 2523
             if (elt == null || haveSeenNode(processed, elt)) {
2266 2524
                 return;
... ...
@@ -2270,35 +2528,14 @@ return (function () {
2270 2528
             if (shouldInclude(elt)) {
2271 2529
                 var name = getRawAttribute(elt,"name");
2272 2530
                 var value = elt.value;
2273
-                if (elt.multiple) {
2531
+                if (elt.multiple && elt.tagName === "SELECT") {
2274 2532
                     value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value });
2275 2533
                 }
2276 2534
                 // include file inputs
2277 2535
                 if (elt.files) {
2278 2536
                     value = toArray(elt.files);
2279 2537
                 }
2280
-                // This is a little ugly because both the current value of the named value in the form
2281
-                // and the new value could be arrays, so we have to handle all four cases :/
2282
-                if (name != null && value != null) {
2283
-                    var current = values[name];
2284
-                    if (current !== undefined) {
2285
-                        if (Array.isArray(current)) {
2286
-                            if (Array.isArray(value)) {
2287
-                                values[name] = current.concat(value);
2288
-                            } else {
2289
-                                current.push(value);
2290
-                            }
2291
-                        } else {
2292
-                            if (Array.isArray(value)) {
2293
-                                values[name] = [current].concat(value);
2294
-                            } else {
2295
-                                values[name] = [current, value];
2296
-                            }
2297
-                        }
2298
-                    } else {
2299
-                        values[name] = value;
2300
-                    }
2301
-                }
2538
+                addValueToValues(name, value, values);
2302 2539
                 if (validate) {
2303 2540
                     validateElement(elt, errors);
2304 2541
                 }
... ...
@@ -2331,6 +2568,9 @@ return (function () {
2331 2568
             var formValues = {};
2332 2569
             var errors = [];
2333 2570
             var internalData = getInternalData(elt);
2571
+            if (internalData.lastButtonClicked && !bodyContains(internalData.lastButtonClicked)) {
2572
+                internalData.lastButtonClicked = null
2573
+            }
2334 2574
 
2335 2575
             // only validate when form is directly submitted and novalidate or formnovalidate are not set
2336 2576
             // or if the element has an explicit hx-validate="true" on it
... ...
@@ -2348,11 +2588,11 @@ return (function () {
2348 2588
             processInputValue(processed, values, errors, elt, validate);
2349 2589
 
2350 2590
             // if a button or submit was clicked last, include its value
2351
-            if (internalData.lastButtonClicked) {
2352
-                var name = getRawAttribute(internalData.lastButtonClicked,"name");
2353
-                if (name) {
2354
-                    values[name] = internalData.lastButtonClicked.value;
2355
-                }
2591
+            if (internalData.lastButtonClicked || elt.tagName === "BUTTON" ||
2592
+                (elt.tagName === "INPUT" && getRawAttribute(elt, "type") === "submit")) {
2593
+                var button = internalData.lastButtonClicked || elt
2594
+                var name = getRawAttribute(button, "name")
2595
+                addValueToValues(name, button.value, formValues)
2356 2596
             }
2357 2597
 
2358 2598
             // include any explicit includes
... ...
@@ -2498,43 +2738,43 @@ return (function () {
2498 2738
                 "swapDelay" : htmx.config.defaultSwapDelay,
2499 2739
                 "settleDelay" : htmx.config.defaultSettleDelay
2500 2740
             }
2501
-            if (getInternalData(elt).boosted && !isAnchorLink(elt)) {
2741
+            if (htmx.config.scrollIntoViewOnBoost && getInternalData(elt).boosted && !isAnchorLink(elt)) {
2502 2742
               swapSpec["show"] = "top"
2503 2743
             }
2504 2744
             if (swapInfo) {
2505 2745
                 var split = splitOnWhitespace(swapInfo);
2506 2746
                 if (split.length > 0) {
2507
-                    swapSpec["swapStyle"] = split[0];
2508
-                    for (var i = 1; i < split.length; i++) {
2509
-                        var modifier = split[i];
2510
-                        if (modifier.indexOf("swap:") === 0) {
2511
-                            swapSpec["swapDelay"] = parseInterval(modifier.substr(5));
2512
-                        }
2513
-                        if (modifier.indexOf("settle:") === 0) {
2514
-                            swapSpec["settleDelay"] = parseInterval(modifier.substr(7));
2515
-                        }
2516
-                        if (modifier.indexOf("transition:") === 0) {
2517
-                            swapSpec["transition"] = modifier.substr(11) === "true";
2518
-                        }
2519
-                        if (modifier.indexOf("scroll:") === 0) {
2520
-                            var scrollSpec = modifier.substr(7);
2747
+                    for (var i = 0; i < split.length; i++) {
2748
+                        var value = split[i];
2749
+                        if (value.indexOf("swap:") === 0) {
2750
+                            swapSpec["swapDelay"] = parseInterval(value.substr(5));
2751
+                        } else if (value.indexOf("settle:") === 0) {
2752
+                            swapSpec["settleDelay"] = parseInterval(value.substr(7));
2753
+                        } else if (value.indexOf("transition:") === 0) {
2754
+                            swapSpec["transition"] = value.substr(11) === "true";
2755
+                        } else if (value.indexOf("ignoreTitle:") === 0) {
2756
+                            swapSpec["ignoreTitle"] = value.substr(12) === "true";
2757
+                        } else if (value.indexOf("scroll:") === 0) {
2758
+                            var scrollSpec = value.substr(7);
2521 2759
                             var splitSpec = scrollSpec.split(":");
2522 2760
                             var scrollVal = splitSpec.pop();
2523 2761
                             var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null;
2524 2762
                             swapSpec["scroll"] = scrollVal;
2525 2763
                             swapSpec["scrollTarget"] = selectorVal;
2526
-                        }
2527
-                        if (modifier.indexOf("show:") === 0) {
2528
-                            var showSpec = modifier.substr(5);
2764
+                        } else if (value.indexOf("show:") === 0) {
2765
+                            var showSpec = value.substr(5);
2529 2766
                             var splitSpec = showSpec.split(":");
2530 2767
                             var showVal = splitSpec.pop();
2531 2768
                             var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null;
2532 2769
                             swapSpec["show"] = showVal;
2533 2770
                             swapSpec["showTarget"] = selectorVal;
2534
-                        }
2535
-                        if (modifier.indexOf("focus-scroll:") === 0) {
2536
-                            var focusScrollVal = modifier.substr("focus-scroll:".length);
2771
+                        } else if (value.indexOf("focus-scroll:") === 0) {
2772
+                            var focusScrollVal = value.substr("focus-scroll:".length);
2537 2773
                             swapSpec["focusScroll"] = focusScrollVal == "true";
2774
+                        } else if (i == 0) {
2775
+                            swapSpec["swapStyle"] = value;
2776
+                        } else {
2777
+                            logError('Unknown modifier in hx-swap: ' + value);
2538 2778
                         }
2539 2779
                     }
2540 2780
                 }
... ...
@@ -2719,7 +2959,7 @@ return (function () {
2719 2959
         }
2720 2960
 
2721 2961
         function hasHeader(xhr, regexp) {
2722
-            return xhr.getAllResponseHeaders().match(regexp);
2962
+            return regexp.test(xhr.getAllResponseHeaders())
2723 2963
         }
2724 2964
 
2725 2965
         function ajaxHelper(verb, path, context) {
... ...
@@ -2738,6 +2978,7 @@ return (function () {
2738 2978
                             values : context.values,
2739 2979
                             targetOverride: resolveTarget(context.target),
2740 2980
                             swapOverride: context.swap,
2981
+                            select: context.select,
2741 2982
                             returnPromise: true
2742 2983
                         });
2743 2984
                 }
... ...
@@ -2757,6 +2998,27 @@ return (function () {
2757 2998
             return arr;
2758 2999
         }
2759 3000
 
3001
+        function verifyPath(elt, path, requestConfig) {
3002
+            var sameHost
3003
+            var url
3004
+            if (typeof URL === "function") {
3005
+                url = new URL(path, document.location.href);
3006
+                var origin = document.location.origin;
3007
+                sameHost = origin === url.origin;
3008
+            } else {
3009
+                // IE11 doesn't support URL
3010
+                url = path
3011
+                sameHost = startsWith(path, document.location.origin)
3012
+            }
3013
+
3014
+            if (htmx.config.selfRequestsOnly) {
3015
+                if (!sameHost) {
3016
+                    return false;
3017
+                }
3018
+            }
3019
+            return triggerEvent(elt, "htmx:validateUrl", mergeObjects({url: url, sameHost: sameHost}, requestConfig));
3020
+        }
3021
+
2760 3022
         function issueAjaxRequest(verb, path, elt, event, etc, confirmed) {
2761 3023
             var resolve = null;
2762 3024
             var reject = null;
... ...
@@ -2771,29 +3033,52 @@ return (function () {
2771 3033
                 elt = getDocument().body;
2772 3034
             }
2773 3035
             var responseHandler = etc.handler || handleAjaxResponse;
3036
+            var select = etc.select || null;
2774 3037
 
2775 3038
             if (!bodyContains(elt)) {
2776
-                return; // do not issue requests for elements removed from the DOM
3039
+                // do not issue requests for elements removed from the DOM
3040
+                maybeCall(resolve);
3041
+                return promise;
2777 3042
             }
2778 3043
             var target = etc.targetOverride || getTarget(elt);
2779 3044
             if (target == null || target == DUMMY_ELT) {
2780 3045
                 triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")});
2781
-                return;
3046
+                maybeCall(reject);
3047
+                return promise;
3048
+            }
3049
+
3050
+            var eltData = getInternalData(elt);
3051
+            var submitter = eltData.lastButtonClicked;
3052
+
3053
+            if (submitter) {
3054
+                var buttonPath = getRawAttribute(submitter, "formaction");
3055
+                if (buttonPath != null) {
3056
+                    path = buttonPath;
3057
+                }
3058
+
3059
+                var buttonVerb = getRawAttribute(submitter, "formmethod")
3060
+                if (buttonVerb != null) {
3061
+                    // ignore buttons with formmethod="dialog"
3062
+                    if (buttonVerb.toLowerCase() !== "dialog") {
3063
+                        verb = buttonVerb;
3064
+                    }
3065
+                }
2782 3066
             }
2783 3067
 
3068
+            var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm");
2784 3069
             // allow event-based confirmation w/ a callback
2785
-            if (!confirmed) {
2786
-                var issueRequest = function() {
2787
-                    return issueAjaxRequest(verb, path, elt, event, etc, true);
3070
+            if (confirmed === undefined) {
3071
+                var issueRequest = function(skipConfirmation) {
3072
+                    return issueAjaxRequest(verb, path, elt, event, etc, !!skipConfirmation);
2788 3073
                 }
2789
-                var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest};
3074
+                var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest, question: confirmQuestion};
2790 3075
                 if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) {
2791
-                    return;
3076
+                    maybeCall(resolve);
3077
+                    return promise;
2792 3078
                 }
2793 3079
             }
2794 3080
 
2795 3081
             var syncElt = elt;
2796
-            var eltData = getInternalData(elt);
2797 3082
             var syncStrategy = getClosestAttributeValue(elt, "hx-sync");
2798 3083
             var queueStrategy = null;
2799 3084
             var abortable = false;
... ...
@@ -2809,10 +3094,12 @@ return (function () {
2809 3094
                 syncStrategy = (syncStrings[1] || 'drop').trim();
2810 3095
                 eltData = getInternalData(syncElt);
2811 3096
                 if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) {
2812
-                    return;
3097
+                    maybeCall(resolve);
3098
+                    return promise;
2813 3099
                 } else if (syncStrategy === "abort") {
2814 3100
                     if (eltData.xhr) {
2815
-                        return;
3101
+                        maybeCall(resolve);
3102
+                        return promise;
2816 3103
                     } else {
2817 3104
                         abortable = true;
2818 3105
                     }
... ...
@@ -2856,7 +3143,8 @@ return (function () {
2856 3143
                             issueAjaxRequest(verb, path, elt, event, etc)
2857 3144
                         });
2858 3145
                     }
2859
-                    return;
3146
+                    maybeCall(resolve);
3147
+                    return promise;
2860 3148
                 }
2861 3149
             }
2862 3150
 
... ...
@@ -2884,8 +3172,7 @@ return (function () {
2884 3172
                 }
2885 3173
             }
2886 3174
 
2887
-            var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm");
2888
-            if (confirmQuestion) {
3175
+            if (confirmQuestion && !confirmed) {
2889 3176
                 if(!confirm(confirmQuestion)) {
2890 3177
                     maybeCall(resolve);
2891 3178
                     endRequestLock()
... ...
@@ -2895,6 +3182,11 @@ return (function () {
2895 3182
 
2896 3183
 
2897 3184
             var headers = getHeaders(elt, target, promptResponse);
3185
+
3186
+            if (verb !== 'get' && !usesFormData(elt)) {
3187
+                headers['Content-Type'] = 'application/x-www-form-urlencoded';
3188
+            }
3189
+
2898 3190
             if (etc.headers) {
2899 3191
                 headers = mergeObjects(headers, etc.headers);
2900 3192
             }
... ...
@@ -2908,10 +3200,6 @@ return (function () {
2908 3200
             var allParameters = mergeObjects(rawParameters, expressionVars);
2909 3201
             var filteredParameters = filterValues(allParameters, elt);
2910 3202
 
2911
-            if (verb !== 'get' && !usesFormData(elt)) {
2912
-                headers['Content-Type'] = 'application/x-www-form-urlencoded';
2913
-            }
2914
-
2915 3203
             if (htmx.config.getCacheBusterParam && verb === 'get') {
2916 3204
                 filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true";
2917 3205
             }
... ...
@@ -2925,8 +3213,12 @@ return (function () {
2925 3213
             var requestAttrValues = getValuesForElement(elt, 'hx-request');
2926 3214
 
2927 3215
             var eltIsBoosted = getInternalData(elt).boosted;
3216
+
3217
+            var useUrlParams = htmx.config.methodsThatUseUrlParams.indexOf(verb) >= 0
3218
+
2928 3219
             var requestConfig = {
2929 3220
                 boosted: eltIsBoosted,
3221
+                useUrlParams: useUrlParams,
2930 3222
                 parameters: filteredParameters,
2931 3223
                 unfilteredParameters: allParameters,
2932 3224
                 headers:headers,
... ...
@@ -2951,6 +3243,7 @@ return (function () {
2951 3243
             headers = requestConfig.headers;
2952 3244
             filteredParameters = requestConfig.parameters;
2953 3245
             errors = requestConfig.errors;
3246
+            useUrlParams = requestConfig.useUrlParams;
2954 3247
 
2955 3248
             if(errors && errors.length > 0){
2956 3249
                 triggerEvent(elt, 'htmx:validation:halted', requestConfig)
... ...
@@ -2962,26 +3255,31 @@ return (function () {
2962 3255
             var splitPath = path.split("#");
2963 3256
             var pathNoAnchor = splitPath[0];
2964 3257
             var anchor = splitPath[1];
2965
-            var finalPathForGet = null;
2966
-            if (verb === 'get') {
2967
-                finalPathForGet = pathNoAnchor;
3258
+
3259
+            var finalPath = path
3260
+            if (useUrlParams) {
3261
+                finalPath = pathNoAnchor;
2968 3262
                 var values = Object.keys(filteredParameters).length !== 0;
2969 3263
                 if (values) {
2970
-                    if (finalPathForGet.indexOf("?") < 0) {
2971
-                        finalPathForGet += "?";
3264
+                    if (finalPath.indexOf("?") < 0) {
3265
+                        finalPath += "?";
2972 3266
                     } else {
2973
-                        finalPathForGet += "&";
3267
+                        finalPath += "&";
2974 3268
                     }
2975
-                    finalPathForGet += urlEncode(filteredParameters);
3269
+                    finalPath += urlEncode(filteredParameters);
2976 3270
                     if (anchor) {
2977
-                        finalPathForGet += "#" + anchor;
3271
+                        finalPath += "#" + anchor;
2978 3272
                     }
2979 3273
                 }
2980
-                xhr.open('GET', finalPathForGet, true);
2981
-            } else {
2982
-                xhr.open(verb.toUpperCase(), path, true);
2983 3274
             }
2984 3275
 
3276
+            if (!verifyPath(elt, finalPath, requestConfig)) {
3277
+                triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig)
3278
+                maybeCall(reject);
3279
+                return promise;
3280
+            };
3281
+
3282
+            xhr.open(verb.toUpperCase(), finalPath, true);
2985 3283
             xhr.overrideMimeType("text/html");
2986 3284
             xhr.withCredentials = requestConfig.withCredentials;
2987 3285
             xhr.timeout = requestConfig.timeout;
... ...
@@ -2999,10 +3297,10 @@ return (function () {
2999 3297
             }
3000 3298
 
3001 3299
             var responseInfo = {
3002
-                xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted,
3300
+                xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted, select: select,
3003 3301
                 pathInfo: {
3004 3302
                     requestPath: path,
3005
-                    finalRequestPath: finalPathForGet || path,
3303
+                    finalRequestPath: finalPath,
3006 3304
                     anchor: anchor
3007 3305
                 }
3008 3306
             };
... ...
@@ -3012,7 +3310,7 @@ return (function () {
3012 3310
                     var hierarchy = hierarchyForElt(elt);
3013 3311
                     responseInfo.pathInfo.responsePath = getPathFromResponse(xhr);
3014 3312
                     responseHandler(elt, responseInfo);
3015
-                    removeRequestIndicatorClasses(indicators);
3313
+                    removeRequestIndicators(indicators, disableElts);
3016 3314
                     triggerEvent(elt, 'htmx:afterRequest', responseInfo);
3017 3315
                     triggerEvent(elt, 'htmx:afterOnLoad', responseInfo);
3018 3316
                     // if the body no longer contains the element, trigger the event on the closest parent
... ...
@@ -3038,21 +3336,21 @@ return (function () {
3038 3336
                 }
3039 3337
             }
3040 3338
             xhr.onerror = function () {
3041
-                removeRequestIndicatorClasses(indicators);
3339
+                removeRequestIndicators(indicators, disableElts);
3042 3340
                 triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo);
3043 3341
                 triggerErrorEvent(elt, 'htmx:sendError', responseInfo);
3044 3342
                 maybeCall(reject);
3045 3343
                 endRequestLock();
3046 3344
             }
3047 3345
             xhr.onabort = function() {
3048
-                removeRequestIndicatorClasses(indicators);
3346
+                removeRequestIndicators(indicators, disableElts);
3049 3347
                 triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo);
3050 3348
                 triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo);
3051 3349
                 maybeCall(reject);
3052 3350
                 endRequestLock();
3053 3351
             }
3054 3352
             xhr.ontimeout = function() {
3055
-                removeRequestIndicatorClasses(indicators);
3353
+                removeRequestIndicators(indicators, disableElts);
3056 3354
                 triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo);
3057 3355
                 triggerErrorEvent(elt, 'htmx:timeout', responseInfo);
3058 3356
                 maybeCall(reject);
... ...
@@ -3064,6 +3362,7 @@ return (function () {
3064 3362
                 return promise
3065 3363
             }
3066 3364
             var indicators = addRequestIndicatorClasses(elt);
3365
+            var disableElts = disableElements(elt);
3067 3366
 
3068 3367
             forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) {
3069 3368
                 forEach([xhr, xhr.upload], function (target) {
... ...
@@ -3077,7 +3376,8 @@ return (function () {
3077 3376
                 });
3078 3377
             });
3079 3378
             triggerEvent(elt, 'htmx:beforeSend', responseInfo);
3080
-            xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters));
3379
+            var params = useUrlParams ? null : encodeParamsForBody(xhr, elt, filteredParameters)
3380
+            xhr.send(params);
3081 3381
             return promise;
3082 3382
         }
3083 3383
 
... ...
@@ -3167,6 +3467,8 @@ return (function () {
3167 3467
             var xhr = responseInfo.xhr;
3168 3468
             var target = responseInfo.target;
3169 3469
             var etc = responseInfo.etc;
3470
+            var requestConfig = responseInfo.requestConfig;
3471
+            var select = responseInfo.select;
3170 3472
 
3171 3473
             if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return;
3172 3474
 
... ...
@@ -3190,20 +3492,25 @@ return (function () {
3190 3492
                 return;
3191 3493
             }
3192 3494
 
3495
+            var shouldRefresh = hasHeader(xhr, /HX-Refresh:/i) && "true" === xhr.getResponseHeader("HX-Refresh");
3496
+
3193 3497
             if (hasHeader(xhr, /HX-Redirect:/i)) {
3194 3498
                 location.href = xhr.getResponseHeader("HX-Redirect");
3499
+                shouldRefresh && location.reload();
3195 3500
                 return;
3196 3501
             }
3197 3502
 
3198
-            if (hasHeader(xhr,/HX-Refresh:/i)) {
3199
-                if ("true" === xhr.getResponseHeader("HX-Refresh")) {
3200
-                    location.reload();
3201
-                    return;
3202
-                }
3503
+            if (shouldRefresh) {
3504
+                location.reload();
3505
+                return;
3203 3506
             }
3204 3507
 
3205 3508
             if (hasHeader(xhr,/HX-Retarget:/i)) {
3206
-                responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget"));
3509
+                if (xhr.getResponseHeader("HX-Retarget") === "this") {
3510
+                    responseInfo.target = elt;
3511
+                } else {
3512
+                    responseInfo.target = querySelectorExt(elt, xhr.getResponseHeader("HX-Retarget"));
3513
+                }
3207 3514
             }
3208 3515
 
3209 3516
             var historyUpdate = determineHistoryUpdates(elt, responseInfo);
... ...
@@ -3215,12 +3522,14 @@ return (function () {
3215 3522
             var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204;
3216 3523
             var serverResponse = xhr.response;
3217 3524
             var isError = xhr.status >= 400;
3218
-            var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo);
3525
+            var ignoreTitle = htmx.config.ignoreTitle
3526
+            var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo);
3219 3527
             if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return;
3220 3528
 
3221 3529
             target = beforeSwapDetails.target; // allow re-targeting
3222 3530
             serverResponse = beforeSwapDetails.serverResponse; // allow updating content
3223 3531
             isError = beforeSwapDetails.isError; // allow updating error
3532
+            ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title
3224 3533
 
3225 3534
             responseInfo.target = target; // Make updated target available to response events
3226 3535
             responseInfo.failed = isError; // Make failed property available to response events
... ...
@@ -3246,6 +3555,10 @@ return (function () {
3246 3555
                 }
3247 3556
                 var swapSpec = getSwapSpecification(elt, swapOverride);
3248 3557
 
3558
+                if (swapSpec.hasOwnProperty('ignoreTitle')) {
3559
+                    ignoreTitle = swapSpec.ignoreTitle;
3560
+                }
3561
+
3249 3562
                 target.classList.add(htmx.config.swappingClass);
3250 3563
 
3251 3564
                 // optional transition API promise callbacks
... ...
@@ -3268,13 +3581,34 @@ return (function () {
3268 3581
                             // safari issue - see https://github.com/microsoft/playwright/issues/5894
3269 3582
                         }
3270 3583
 
3584
+                        var selectOverride;
3585
+                        if (select) {
3586
+                            selectOverride = select;
3587
+                        }
3588
+
3589
+                        if (hasHeader(xhr, /HX-Reselect:/i)) {
3590
+                            selectOverride = xhr.getResponseHeader("HX-Reselect");
3591
+                        }
3592
+
3593
+                        // if we need to save history, do so, before swapping so that relative resources have the correct base URL
3594
+                        if (historyUpdate.type) {
3595
+                            triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo));
3596
+                            if (historyUpdate.type === "push") {
3597
+                                pushUrlIntoHistory(historyUpdate.path);
3598
+                                triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path});
3599
+                            } else {
3600
+                                replaceUrlInHistory(historyUpdate.path);
3601
+                                triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path});
3602
+                            }
3603
+                        }
3604
+
3271 3605
                         var settleInfo = makeSettleInfo(target);
3272
-                        selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo);
3606
+                        selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo, selectOverride);
3273 3607
 
3274 3608
                         if (selectionInfo.elt &&
3275 3609
                             !bodyContains(selectionInfo.elt) &&
3276
-                            selectionInfo.elt.id) {
3277
-                            var newActiveElt = document.getElementById(selectionInfo.elt.id);
3610
+                            getRawAttribute(selectionInfo.elt, "id")) {
3611
+                            var newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, "id"));
3278 3612
                             var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll };
3279 3613
                             if (newActiveElt) {
3280 3614
                                 // @ts-ignore
... ...
@@ -3317,24 +3651,14 @@ return (function () {
3317 3651
                                 triggerEvent(elt, 'htmx:afterSettle', responseInfo);
3318 3652
                             });
3319 3653
 
3320
-                            // if we need to save history, do so
3321
-                            if (historyUpdate.type) {
3322
-                                if (historyUpdate.type === "push") {
3323
-                                    pushUrlIntoHistory(historyUpdate.path);
3324
-                                    triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path});
3325
-                                } else {
3326
-                                    replaceUrlInHistory(historyUpdate.path);
3327
-                                    triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path});
3328
-                                }
3329
-                            }
3330 3654
                             if (responseInfo.pathInfo.anchor) {
3331
-                                var anchorTarget = find("#" + responseInfo.pathInfo.anchor);
3655
+                                var anchorTarget = getDocument().getElementById(responseInfo.pathInfo.anchor);
3332 3656
                                 if(anchorTarget) {
3333 3657
                                     anchorTarget.scrollIntoView({block:'start', behavior: "auto"});
3334 3658
                                 }
3335 3659
                             }
3336 3660
 
3337
-                            if(settleInfo.title) {
3661
+                            if(settleInfo.title && !ignoreTitle) {
3338 3662
                                 var titleElt = find("title");
3339 3663
                                 if(titleElt) {
3340 3664
                                     titleElt.innerHTML = settleInfo.title;
... ...
@@ -3485,9 +3809,22 @@ return (function () {
3485 3809
         //====================================================================
3486 3810
         // Initialization
3487 3811
         //====================================================================
3812
+        var isReady = false
3813
+        getDocument().addEventListener('DOMContentLoaded', function() {
3814
+            isReady = true
3815
+        })
3488 3816
 
3817
+        /**
3818
+         * Execute a function now if DOMContentLoaded has fired, otherwise listen for it.
3819
+         *
3820
+         * This function uses isReady because there is no realiable way to ask the browswer whether
3821
+         * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded
3822
+         * firing and readystate=complete.
3823
+         */
3489 3824
         function ready(fn) {
3490
-            if (getDocument().readyState !== 'loading') {
3825
+            // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by
3826
+            // some means other than the initial page load.
3827
+            if (isReady || getDocument().readyState === 'complete') {
3491 3828
                 fn();
3492 3829
             } else {
3493 3830
                 getDocument().addEventListener('DOMContentLoaded', fn);
... ...
@@ -3498,9 +3835,9 @@ return (function () {
3498 3835
             if (htmx.config.includeIndicatorStyles !== false) {
3499 3836
                 getDocument().head.insertAdjacentHTML("beforeend",
3500 3837
                     "<style>\
3501
-                      ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\
3502
-                      ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\
3503
-                      ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\
3838
+                      ." + htmx.config.indicatorClass + "{opacity:0}\
3839
+                      ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\
3840
+                      ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1; transition: opacity 200ms ease-in;}\
3504 3841
                     </style>");
3505 3842
             }
3506 3843
         }
... ...
@@ -3538,7 +3875,9 @@ return (function () {
3538 3875
                     internalData.xhr.abort();
3539 3876
                 }
3540 3877
             });
3541
-            var originalPopstate = window.onpopstate;
3878
+            /** @type {(ev: PopStateEvent) => any} */
3879
+            const originalPopstate = window.onpopstate ? window.onpopstate.bind(window) : null;
3880
+            /** @type {(ev: PopStateEvent) => any} */
3542 3881
             window.onpopstate = function (event) {
3543 3882
                 if (event.state && event.state.htmx) {
3544 3883
                     restoreHistory();
Browse code

Initial htmx npm packages installation

Benjamin Roth authored on25/05/2023 09:52:13
Showing1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,3566 @@
1
+// UMD insanity
2
+// This code sets up support for (in order) AMD, ES6 modules, and globals.
3
+(function (root, factory) {
4
+    //@ts-ignore
5
+    if (typeof define === 'function' && define.amd) {
6
+        // AMD. Register as an anonymous module.
7
+        //@ts-ignore
8
+        define([], factory);
9
+    } else if (typeof module === 'object' && module.exports) {
10
+        // Node. Does not work with strict CommonJS, but
11
+        // only CommonJS-like environments that support module.exports,
12
+        // like Node.
13
+        module.exports = factory();
14
+    } else {
15
+        // Browser globals
16
+        root.htmx = root.htmx || factory();
17
+    }
18
+}(typeof self !== 'undefined' ? self : this, function () {
19
+return (function () {
20
+        'use strict';
21
+
22
+        // Public API
23
+        //** @type {import("./htmx").HtmxApi} */
24
+        // TODO: list all methods in public API
25
+        var htmx = {
26
+            onLoad: onLoadHelper,
27
+            process: processNode,
28
+            on: addEventListenerImpl,
29
+            off: removeEventListenerImpl,
30
+            trigger : triggerEvent,
31
+            ajax : ajaxHelper,
32
+            find : find,
33
+            findAll : findAll,
34
+            closest : closest,
35
+            values : function(elt, type){
36
+                var inputValues = getInputValues(elt, type || "post");
37
+                return inputValues.values;
38
+            },
39
+            remove : removeElement,
40
+            addClass : addClassToElement,
41
+            removeClass : removeClassFromElement,
42
+            toggleClass : toggleClassOnElement,
43
+            takeClass : takeClassForElement,
44
+            defineExtension : defineExtension,
45
+            removeExtension : removeExtension,
46
+            logAll : logAll,
47
+            logger : null,
48
+            config : {
49
+                historyEnabled:true,
50
+                historyCacheSize:10,
51
+                refreshOnHistoryMiss:false,
52
+                defaultSwapStyle:'innerHTML',
53
+                defaultSwapDelay:0,
54
+                defaultSettleDelay:20,
55
+                includeIndicatorStyles:true,
56
+                indicatorClass:'htmx-indicator',
57
+                requestClass:'htmx-request',
58
+                addedClass:'htmx-added',
59
+                settlingClass:'htmx-settling',
60
+                swappingClass:'htmx-swapping',
61
+                allowEval:true,
62
+                inlineScriptNonce:'',
63
+                attributesToSettle:["class", "style", "width", "height"],
64
+                withCredentials:false,
65
+                timeout:0,
66
+                wsReconnectDelay: 'full-jitter',
67
+                wsBinaryType: 'blob',
68
+                disableSelector: "[hx-disable], [data-hx-disable]",
69
+                useTemplateFragments: false,
70
+                scrollBehavior: 'smooth',
71
+                defaultFocusScroll: false,
72
+                getCacheBusterParam: false,
73
+                globalViewTransitions: false,
74
+            },
75
+            parseInterval:parseInterval,
76
+            _:internalEval,
77
+            createEventSource: function(url){
78
+                return new EventSource(url, {withCredentials:true})
79
+            },
80
+            createWebSocket: function(url){
81
+                var sock = new WebSocket(url, []);
82
+                sock.binaryType = htmx.config.wsBinaryType;
83
+                return sock;
84
+            },
85
+            version: "1.9.2"
86
+        };
87
+
88
+        /** @type {import("./htmx").HtmxInternalApi} */
89
+        var internalAPI = {
90
+            addTriggerHandler: addTriggerHandler,
91
+            bodyContains: bodyContains,
92
+            canAccessLocalStorage: canAccessLocalStorage,
93
+            filterValues: filterValues,
94
+            hasAttribute: hasAttribute,
95
+            getAttributeValue: getAttributeValue,
96
+            getClosestMatch: getClosestMatch,
97
+            getExpressionVars: getExpressionVars,
98
+            getHeaders: getHeaders,
99
+            getInputValues: getInputValues,
100
+            getInternalData: getInternalData,
101
+            getSwapSpecification: getSwapSpecification,
102
+            getTriggerSpecs: getTriggerSpecs,
103
+            getTarget: getTarget,
104
+            makeFragment: makeFragment,
105
+            mergeObjects: mergeObjects,
106
+            makeSettleInfo: makeSettleInfo,
107
+            oobSwap: oobSwap,
108
+            selectAndSwap: selectAndSwap,
109
+            settleImmediately: settleImmediately,
110
+            shouldCancel: shouldCancel,
111
+            triggerEvent: triggerEvent,
112
+            triggerErrorEvent: triggerErrorEvent,
113
+            withExtensions: withExtensions,
114
+        }
115
+
116
+        var VERBS = ['get', 'post', 'put', 'delete', 'patch'];
117
+        var VERB_SELECTOR = VERBS.map(function(verb){
118
+            return "[hx-" + verb + "], [data-hx-" + verb + "]"
119
+        }).join(", ");
120
+
121
+        //====================================================================
122
+        // Utilities
123
+        //====================================================================
124
+
125
+        function parseInterval(str) {
126
+            if (str == undefined)  {
127
+                return undefined
128
+            }
129
+            if (str.slice(-2) == "ms") {
130
+                return parseFloat(str.slice(0,-2)) || undefined
131
+            }
132
+            if (str.slice(-1) == "s") {
133
+                return (parseFloat(str.slice(0,-1)) * 1000) || undefined
134
+            }
135
+            if (str.slice(-1) == "m") {
136
+                return (parseFloat(str.slice(0,-1)) * 1000 * 60) || undefined
137
+            }
138
+            return parseFloat(str) || undefined
139
+        }
140
+
141
+        /**
142
+         * @param {HTMLElement} elt
143
+         * @param {string} name
144
+         * @returns {(string | null)}
145
+         */
146
+        function getRawAttribute(elt, name) {
147
+            return elt.getAttribute && elt.getAttribute(name);
148
+        }
149
+
150
+        // resolve with both hx and data-hx prefixes
151
+        function hasAttribute(elt, qualifiedName) {
152
+            return elt.hasAttribute && (elt.hasAttribute(qualifiedName) ||
153
+                elt.hasAttribute("data-" + qualifiedName));
154
+        }
155
+
156
+        /**
157
+         *
158
+         * @param {HTMLElement} elt
159
+         * @param {string} qualifiedName
160
+         * @returns {(string | null)}
161
+         */
162
+        function getAttributeValue(elt, qualifiedName) {
163
+            return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName);
164
+        }
165
+
166
+        /**
167
+         * @param {HTMLElement} elt
168
+         * @returns {HTMLElement | null}
169
+         */
170
+        function parentElt(elt) {
171
+            return elt.parentElement;
172
+        }
173
+
174
+        /**
175
+         * @returns {Document}
176
+         */
177
+        function getDocument() {
178
+            return document;
179
+        }
180
+
181
+        /**
182
+         * @param {HTMLElement} elt
183
+         * @param {(e:HTMLElement) => boolean} condition
184
+         * @returns {HTMLElement | null}
185
+         */
186
+        function getClosestMatch(elt, condition) {
187
+            while (elt && !condition(elt)) {
188
+                elt = parentElt(elt);
189
+            }
190
+
191
+            return elt ? elt : null;
192
+        }
193
+
194
+        function getAttributeValueWithDisinheritance(initialElement, ancestor, attributeName){
195
+            var attributeValue = getAttributeValue(ancestor, attributeName);
196
+            var disinherit = getAttributeValue(ancestor, "hx-disinherit");
197
+            if (initialElement !== ancestor && disinherit && (disinherit === "*" || disinherit.split(" ").indexOf(attributeName) >= 0)) {
198
+                return "unset";
199
+            } else {
200
+                return attributeValue
201
+            }
202
+        }
203
+
204
+        /**
205
+         * @param {HTMLElement} elt
206
+         * @param {string} attributeName
207
+         * @returns {string | null}
208
+         */
209
+        function getClosestAttributeValue(elt, attributeName) {
210
+            var closestAttr = null;
211
+            getClosestMatch(elt, function (e) {
212
+                return closestAttr = getAttributeValueWithDisinheritance(elt, e, attributeName);
213
+            });
214
+            if (closestAttr !== "unset") {
215
+                return closestAttr;
216
+            }
217
+        }
218
+
219
+        /**
220
+         * @param {HTMLElement} elt
221
+         * @param {string} selector
222
+         * @returns {boolean}
223
+         */
224
+        function matches(elt, selector) {
225
+            // @ts-ignore: non-standard properties for browser compatability
226
+            // noinspection JSUnresolvedVariable
227
+            var matchesFunction = elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector;
228
+            return matchesFunction && matchesFunction.call(elt, selector);
229
+        }
230
+
231
+        /**
232
+         * @param {string} str
233
+         * @returns {string}
234
+         */
235
+        function getStartTag(str) {
236
+            var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i
237
+            var match = tagMatcher.exec( str );
238
+            if (match) {
239
+                return match[1].toLowerCase();
240
+            } else {
241
+                return "";
242
+            }
243
+        }
244
+
245
+        /**
246
+         *
247
+         * @param {string} resp
248
+         * @param {number} depth
249
+         * @returns {Element}
250
+         */
251
+        function parseHTML(resp, depth) {
252
+            var parser = new DOMParser();
253
+            var responseDoc = parser.parseFromString(resp, "text/html");
254
+
255
+            /** @type {Element} */
256
+            var responseNode = responseDoc.body;
257
+            while (depth > 0) {
258
+                depth--;
259
+                // @ts-ignore
260
+                responseNode = responseNode.firstChild;
261
+            }
262
+            if (responseNode == null) {
263
+                // @ts-ignore
264
+                responseNode = getDocument().createDocumentFragment();
265
+            }
266
+            return responseNode;
267
+        }
268
+
269
+        function aFullPageResponse(resp) {
270
+            return resp.match(/<body/);
271
+        }
272
+
273
+        /**
274
+         *
275
+         * @param {string} resp
276
+         * @returns {Element}
277
+         */
278
+        function makeFragment(resp) {
279
+            var partialResponse = !aFullPageResponse(resp);
280
+            if (htmx.config.useTemplateFragments && partialResponse) {
281
+                var documentFragment = parseHTML("<body><template>" + resp + "</template></body>", 0);
282
+                // @ts-ignore type mismatch between DocumentFragment and Element.
283
+                // TODO: Are these close enough for htmx to use interchangably?
284
+                return documentFragment.querySelector('template').content;
285
+            } else {
286
+                var startTag = getStartTag(resp);
287
+                switch (startTag) {
288
+                    case "thead":
289
+                    case "tbody":
290
+                    case "tfoot":
291
+                    case "colgroup":
292
+                    case "caption":
293
+                        return parseHTML("<table>" + resp + "</table>", 1);
294
+                    case "col":
295
+                        return parseHTML("<table><colgroup>" + resp + "</colgroup></table>", 2);
296
+                    case "tr":
297
+                        return parseHTML("<table><tbody>" + resp + "</tbody></table>", 2);
298
+                    case "td":
299
+                    case "th":
300
+                        return parseHTML("<table><tbody><tr>" + resp + "</tr></tbody></table>", 3);
301
+                    case "script":
302
+                        return parseHTML("<div>" + resp + "</div>", 1);
303
+                    default:
304
+                        return parseHTML(resp, 0);
305
+                }
306
+            }
307
+        }
308
+
309
+        /**
310
+         * @param {Function} func
311
+         */
312
+        function maybeCall(func){
313
+            if(func) {
314
+                func();
315
+            }
316
+        }
317
+
318
+        /**
319
+         * @param {any} o
320
+         * @param {string} type
321
+         * @returns
322
+         */
323
+        function isType(o, type) {
324
+            return Object.prototype.toString.call(o) === "[object " + type + "]";
325
+        }
326
+
327
+        /**
328
+         * @param {*} o
329
+         * @returns {o is Function}
330
+         */
331
+        function isFunction(o) {
332
+            return isType(o, "Function");
333
+        }
334
+
335
+        /**
336
+         * @param {*} o
337
+         * @returns {o is Object}
338
+         */
339
+        function isRawObject(o) {
340
+            return isType(o, "Object");
341
+        }
342
+
343
+        /**
344
+         * getInternalData retrieves "private" data stored by htmx within an element
345
+         * @param {HTMLElement} elt
346
+         * @returns {*}
347
+         */
348
+        function getInternalData(elt) {
349
+            var dataProp = 'htmx-internal-data';
350
+            var data = elt[dataProp];
351
+            if (!data) {
352
+                data = elt[dataProp] = {};
353
+            }
354
+            return data;
355
+        }
356
+
357
+        /**
358
+         * toArray converts an ArrayLike object into a real array.
359
+         * @param {ArrayLike} arr
360
+         * @returns {any[]}
361
+         */
362
+        function toArray(arr) {
363
+            var returnArr = [];
364
+            if (arr) {
365
+                for (var i = 0; i < arr.length; i++) {
366
+                    returnArr.push(arr[i]);
367
+                }
368
+            }
369
+            return returnArr
370
+        }
371
+
372
+        function forEach(arr, func) {
373
+            if (arr) {
374
+                for (var i = 0; i < arr.length; i++) {
375
+                    func(arr[i]);
376
+                }
377
+            }
378
+        }
379
+
380
+        function isScrolledIntoView(el) {
381
+            var rect = el.getBoundingClientRect();
382
+            var elemTop = rect.top;
383
+            var elemBottom = rect.bottom;
384
+            return elemTop < window.innerHeight && elemBottom >= 0;
385
+        }
386
+
387
+        function bodyContains(elt) {
388
+            // IE Fix
389
+            if (elt.getRootNode && elt.getRootNode() instanceof ShadowRoot) {
390
+                return getDocument().body.contains(elt.getRootNode().host);
391
+            } else {
392
+                return getDocument().body.contains(elt);
393
+            }
394
+        }
395
+
396
+        function splitOnWhitespace(trigger) {
397
+            return trigger.trim().split(/\s+/);
398
+        }
399
+
400
+        /**
401
+         * mergeObjects takes all of the keys from
402
+         * obj2 and duplicates them into obj1
403
+         * @param {Object} obj1
404
+         * @param {Object} obj2
405
+         * @returns {Object}
406
+         */
407
+        function mergeObjects(obj1, obj2) {
408
+            for (var key in obj2) {
409
+                if (obj2.hasOwnProperty(key)) {
410
+                    obj1[key] = obj2[key];
411
+                }
412
+            }
413
+            return obj1;
414
+        }
415
+
416
+        function parseJSON(jString) {
417
+            try {
418
+                return JSON.parse(jString);
419
+            } catch(error) {
420
+                logError(error);
421
+                return null;
422
+            }
423
+        }
424
+
425
+        function canAccessLocalStorage() {
426
+            var test = 'htmx:localStorageTest';
427
+            try {
428
+                localStorage.setItem(test, test);
429
+                localStorage.removeItem(test);
430
+                return true;
431
+            } catch(e) {
432
+                return false;
433
+            }
434
+        }
435
+
436
+        function normalizePath(path) {
437
+            try {
438
+                var url = new URL(path);
439
+                if (url) {
440
+                    path = url.pathname + url.search;
441
+                }
442
+                // remove trailing slash, unless index page
443
+                if (!path.match('^/$')) {
444
+                    path = path.replace(/\/+$/, '');
445
+                }
446
+                return path;
447
+            } catch (e) {
448
+                // be kind to IE11, which doesn't support URL()
449
+                return path;
450
+            }
451
+        }
452
+
453
+        //==========================================================================================
454
+        // public API
455
+        //==========================================================================================
456
+
457
+        function internalEval(str){
458
+            return maybeEval(getDocument().body, function () {
459
+                return eval(str);
460
+            });
461
+        }
462
+
463
+        function onLoadHelper(callback) {
464
+            var value = htmx.on("htmx:load", function(evt) {
465
+                callback(evt.detail.elt);
466
+            });
467
+            return value;
468
+        }
469
+
470
+        function logAll(){
471
+            htmx.logger = function(elt, event, data) {
472
+                if(console) {
473
+                    console.log(event, elt, data);
474
+                }
475
+            }
476
+        }
477
+
478
+        function find(eltOrSelector, selector) {
479
+            if (selector) {
480
+                return eltOrSelector.querySelector(selector);
481
+            } else {
482
+                return find(getDocument(), eltOrSelector);
483
+            }
484
+        }
485
+
486
+        function findAll(eltOrSelector, selector) {
487
+            if (selector) {
488
+                return eltOrSelector.querySelectorAll(selector);
489
+            } else {
490
+                return findAll(getDocument(), eltOrSelector);
491
+            }
492
+        }
493
+
494
+        function removeElement(elt, delay) {
495
+            elt = resolveTarget(elt);
496
+            if (delay) {
497
+                setTimeout(function(){
498
+                    removeElement(elt);
499
+                    elt = null;
500
+                }, delay);
501
+            } else {
502
+                elt.parentElement.removeChild(elt);
503
+            }
504
+        }
505
+
506
+        function addClassToElement(elt, clazz, delay) {
507
+            elt = resolveTarget(elt);
508
+            if (delay) {
509
+                setTimeout(function(){
510
+                    addClassToElement(elt, clazz);
511
+                    elt = null;
512
+                }, delay);
513
+            } else {
514
+                elt.classList && elt.classList.add(clazz);
515
+            }
516
+        }
517
+
518
+        function removeClassFromElement(elt, clazz, delay) {
519
+            elt = resolveTarget(elt);
520
+            if (delay) {
521
+                setTimeout(function(){
522
+                    removeClassFromElement(elt, clazz);
523
+                    elt = null;
524
+                }, delay);
525
+            } else {
526
+                if (elt.classList) {
527
+                    elt.classList.remove(clazz);
528
+                    // if there are no classes left, remove the class attribute
529
+                    if (elt.classList.length === 0) {
530
+                        elt.removeAttribute("class");
531
+                    }
532
+                }
533
+            }
534
+        }
535
+
536
+        function toggleClassOnElement(elt, clazz) {
537
+            elt = resolveTarget(elt);
538
+            elt.classList.toggle(clazz);
539
+        }
540
+
541
+        function takeClassForElement(elt, clazz) {
542
+            elt = resolveTarget(elt);
543
+            forEach(elt.parentElement.children, function(child){
544
+                removeClassFromElement(child, clazz);
545
+            })
546
+            addClassToElement(elt, clazz);
547
+        }
548
+
549
+        function closest(elt, selector) {
550
+            elt = resolveTarget(elt);
551
+            if (elt.closest) {
552
+                return elt.closest(selector);
553
+            } else {
554
+                // TODO remove when IE goes away
555
+                do{
556
+                    if (elt == null || matches(elt, selector)){
557
+                        return elt;
558
+                    }
559
+                }
560
+                while (elt = elt && parentElt(elt));
561
+                return null;
562
+            }
563
+        }
564
+
565
+        function normalizeSelector(selector) {
566
+            var trimmedSelector = selector.trim();
567
+            if (trimmedSelector.startsWith("<") && trimmedSelector.endsWith("/>")) {
568
+                return trimmedSelector.substring(1, trimmedSelector.length - 2);
569
+            } else {
570
+                return trimmedSelector;
571
+            }
572
+        }
573
+
574
+        function querySelectorAllExt(elt, selector) {
575
+            if (selector.indexOf("closest ") === 0) {
576
+                return [closest(elt, normalizeSelector(selector.substr(8)))];
577
+            } else if (selector.indexOf("find ") === 0) {
578
+                return [find(elt, normalizeSelector(selector.substr(5)))];
579
+            } else if (selector.indexOf("next ") === 0) {
580
+                return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))];
581
+            } else if (selector.indexOf("previous ") === 0) {
582
+                return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))];
583
+            } else if (selector === 'document') {
584
+                return [document];
585
+            } else if (selector === 'window') {
586
+                return [window];
587
+            } else {
588
+                return getDocument().querySelectorAll(normalizeSelector(selector));
589
+            }
590
+        }
591
+
592
+        var scanForwardQuery = function(start, match) {
593
+            var results = getDocument().querySelectorAll(match);
594
+            for (var i = 0; i < results.length; i++) {
595
+                var elt = results[i];
596
+                if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) {
597
+                    return elt;
598
+                }
599
+            }
600
+        }
601
+
602
+        var scanBackwardsQuery = function(start, match) {
603
+            var results = getDocument().querySelectorAll(match);
604
+            for (var i = results.length - 1; i >= 0; i--) {
605
+                var elt = results[i];
606
+                if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) {
607
+                    return elt;
608
+                }
609
+            }
610
+        }
611
+
612
+        function querySelectorExt(eltOrSelector, selector) {
613
+            if (selector) {
614
+                return querySelectorAllExt(eltOrSelector, selector)[0];
615
+            } else {
616
+                return querySelectorAllExt(getDocument().body, eltOrSelector)[0];
617
+            }
618
+        }
619
+
620
+        function resolveTarget(arg2) {
621
+            if (isType(arg2, 'String')) {
622
+                return find(arg2);
623
+            } else {
624
+                return arg2;
625
+            }
626
+        }
627
+
628
+        function processEventArgs(arg1, arg2, arg3) {
629
+            if (isFunction(arg2)) {
630
+                return {
631
+                    target: getDocument().body,
632
+                    event: arg1,
633
+                    listener: arg2
634
+                }
635
+            } else {
636
+                return {
637
+                    target: resolveTarget(arg1),
638
+                    event: arg2,
639
+                    listener: arg3
640
+                }
641
+            }
642
+
643
+        }
644
+
645
+        function addEventListenerImpl(arg1, arg2, arg3) {
646
+            ready(function(){
647
+                var eventArgs = processEventArgs(arg1, arg2, arg3);
648
+                eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener);
649
+            })
650
+            var b = isFunction(arg2);
651
+            return b ? arg2 : arg3;
652
+        }
653
+
654
+        function removeEventListenerImpl(arg1, arg2, arg3) {
655
+            ready(function(){
656
+                var eventArgs = processEventArgs(arg1, arg2, arg3);
657
+                eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener);
658
+            })
659
+            return isFunction(arg2) ? arg2 : arg3;
660
+        }
661
+
662
+        //====================================================================
663
+        // Node processing
664
+        //====================================================================
665
+
666
+        var DUMMY_ELT = getDocument().createElement("output"); // dummy element for bad selectors
667
+        function findAttributeTargets(elt, attrName) {
668
+            var attrTarget = getClosestAttributeValue(elt, attrName);
669
+            if (attrTarget) {
670
+                if (attrTarget === "this") {
671
+                    return [findThisElement(elt, attrName)];
672
+                } else {
673
+                    var result = querySelectorAllExt(elt, attrTarget);
674
+                    if (result.length === 0) {
675
+                        logError('The selector "' + attrTarget + '" on ' + attrName + " returned no matches!");
676
+                        return [DUMMY_ELT]
677
+                    } else {
678
+                        return result;
679
+                    }
680
+                }
681
+            }
682
+        }
683
+
684
+        function findThisElement(elt, attribute){
685
+            return getClosestMatch(elt, function (elt) {
686
+                return getAttributeValue(elt, attribute) != null;
687
+            })
688
+        }
689
+
690
+        function getTarget(elt) {
691
+            var targetStr = getClosestAttributeValue(elt, "hx-target");
692
+            if (targetStr) {
693
+                if (targetStr === "this") {
694
+                    return findThisElement(elt,'hx-target');
695
+                } else {
696
+                    return querySelectorExt(elt, targetStr)
697
+                }
698
+            } else {
699
+                var data = getInternalData(elt);
700
+                if (data.boosted) {
701
+                    return getDocument().body;
702
+                } else {
703
+                    return elt;
704
+                }
705
+            }
706
+        }
707
+
708
+        function shouldSettleAttribute(name) {
709
+            var attributesToSettle = htmx.config.attributesToSettle;
710
+            for (var i = 0; i < attributesToSettle.length; i++) {
711
+                if (name === attributesToSettle[i]) {
712
+                    return true;
713
+                }
714
+            }
715
+            return false;
716
+        }
717
+
718
+        function cloneAttributes(mergeTo, mergeFrom) {
719
+            forEach(mergeTo.attributes, function (attr) {
720
+                if (!mergeFrom.hasAttribute(attr.name) && shouldSettleAttribute(attr.name)) {
721
+                    mergeTo.removeAttribute(attr.name)
722
+                }
723
+            });
724
+            forEach(mergeFrom.attributes, function (attr) {
725
+                if (shouldSettleAttribute(attr.name)) {
726
+                    mergeTo.setAttribute(attr.name, attr.value);
727
+                }
728
+            });
729
+        }
730
+
731
+        function isInlineSwap(swapStyle, target) {
732
+            var extensions = getExtensions(target);
733
+            for (var i = 0; i < extensions.length; i++) {
734
+                var extension = extensions[i];
735
+                try {
736
+                    if (extension.isInlineSwap(swapStyle)) {
737
+                        return true;
738
+                    }
739
+                } catch(e) {
740
+                    logError(e);
741
+                }
742
+            }
743
+            return swapStyle === "outerHTML";
744
+        }
745
+
746
+        /**
747
+         *
748
+         * @param {string} oobValue
749
+         * @param {HTMLElement} oobElement
750
+         * @param {*} settleInfo
751
+         * @returns
752
+         */
753
+        function oobSwap(oobValue, oobElement, settleInfo) {
754
+            var selector = "#" + oobElement.id;
755
+            var swapStyle = "outerHTML";
756
+            if (oobValue === "true") {
757
+                // do nothing
758
+            } else if (oobValue.indexOf(":") > 0) {
759
+                swapStyle = oobValue.substr(0, oobValue.indexOf(":"));
760
+                selector  = oobValue.substr(oobValue.indexOf(":") + 1, oobValue.length);
761
+            } else {
762
+                swapStyle = oobValue;
763
+            }
764
+
765
+            var targets = getDocument().querySelectorAll(selector);
766
+            if (targets) {
767
+                forEach(
768
+                    targets,
769
+                    function (target) {
770
+                        var fragment;
771
+                        var oobElementClone = oobElement.cloneNode(true);
772
+                        fragment = getDocument().createDocumentFragment();
773
+                        fragment.appendChild(oobElementClone);
774
+                        if (!isInlineSwap(swapStyle, target)) {
775
+                            fragment = oobElementClone; // if this is not an inline swap, we use the content of the node, not the node itself
776
+                        }
777
+
778
+                        var beforeSwapDetails = {shouldSwap: true, target: target, fragment:fragment };
779
+                        if (!triggerEvent(target, 'htmx:oobBeforeSwap', beforeSwapDetails)) return;
780
+
781
+                        target = beforeSwapDetails.target; // allow re-targeting
782
+                        if (beforeSwapDetails['shouldSwap']){
783
+                            swap(swapStyle, target, target, fragment, settleInfo);
784
+                        }
785
+                        forEach(settleInfo.elts, function (elt) {
786
+                            triggerEvent(elt, 'htmx:oobAfterSwap', beforeSwapDetails);
787
+                        });
788
+                    }
789
+                );
790
+                oobElement.parentNode.removeChild(oobElement);
791
+            } else {
792
+                oobElement.parentNode.removeChild(oobElement);
793
+                triggerErrorEvent(getDocument().body, "htmx:oobErrorNoTarget", {content: oobElement});
794
+            }
795
+            return oobValue;
796
+        }
797
+
798
+        function handleOutOfBandSwaps(elt, fragment, settleInfo) {
799
+            var oobSelects = getClosestAttributeValue(elt, "hx-select-oob");
800
+            if (oobSelects) {
801
+                var oobSelectValues = oobSelects.split(",");
802
+                for (let i = 0; i < oobSelectValues.length; i++) {
803
+                    var oobSelectValue = oobSelectValues[i].split(":", 2);
804
+                    var id = oobSelectValue[0].trim();
805
+                    if (id.indexOf("#") === 0) {
806
+                        id = id.substring(1);
807
+                    }
808
+                    var oobValue = oobSelectValue[1] || "true";
809
+                    var oobElement = fragment.querySelector("#" + id);
810
+                    if (oobElement) {
811
+                        oobSwap(oobValue, oobElement, settleInfo);
812
+                    }
813
+                }
814
+            }
815
+            forEach(findAll(fragment, '[hx-swap-oob], [data-hx-swap-oob]'), function (oobElement) {
816
+                var oobValue = getAttributeValue(oobElement, "hx-swap-oob");
817
+                if (oobValue != null) {
818
+                    oobSwap(oobValue, oobElement, settleInfo);
819
+                }
820
+            });
821
+        }
822
+
823
+        function handlePreservedElements(fragment) {
824
+            forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) {
825
+                var id = getAttributeValue(preservedElt, "id");
826
+                var oldElt = getDocument().getElementById(id);
827
+                if (oldElt != null) {
828
+                    preservedElt.parentNode.replaceChild(oldElt, preservedElt);
829
+                }
830
+            });
831
+        }
832
+
833
+        function handleAttributes(parentNode, fragment, settleInfo) {
834
+            forEach(fragment.querySelectorAll("[id]"), function (newNode) {
835
+                if (newNode.id && newNode.id.length > 0) {
836
+                    var normalizedId = newNode.id.replace("'", "\\'");
837
+                    var normalizedTag = newNode.tagName.replace(':', '\\:');
838
+                    var oldNode = parentNode.querySelector(normalizedTag + "[id='" + normalizedId + "']");
839
+                    if (oldNode && oldNode !== parentNode) {
840
+                        var newAttributes = newNode.cloneNode();
841
+                        cloneAttributes(newNode, oldNode);
842
+                        settleInfo.tasks.push(function () {
843
+                            cloneAttributes(newNode, newAttributes);
844
+                        });
845
+                    }
846
+                }
847
+            });
848
+        }
849
+
850
+        function makeAjaxLoadTask(child) {
851
+            return function () {
852
+                removeClassFromElement(child, htmx.config.addedClass);
853
+                processNode(child);
854
+                processScripts(child);
855
+                processFocus(child)
856
+                triggerEvent(child, 'htmx:load');
857
+            };
858
+        }
859
+
860
+        function processFocus(child) {
861
+            var autofocus = "[autofocus]";
862
+            var autoFocusedElt = matches(child, autofocus) ? child : child.querySelector(autofocus)
863
+            if (autoFocusedElt != null) {
864
+                autoFocusedElt.focus();
865
+            }
866
+        }
867
+
868
+        function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
869
+            handleAttributes(parentNode, fragment, settleInfo);
870
+            while(fragment.childNodes.length > 0){
871
+                var child = fragment.firstChild;
872
+                addClassToElement(child, htmx.config.addedClass);
873
+                parentNode.insertBefore(child, insertBefore);
874
+                if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) {
875
+                    settleInfo.tasks.push(makeAjaxLoadTask(child));
876
+                }
877
+            }
878
+        }
879
+
880
+        // based on https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0,
881
+        // derived from Java's string hashcode implementation
882
+        function stringHash(string, hash) {
883
+            var char = 0;
884
+            while (char < string.length){
885
+                hash = (hash << 5) - hash + string.charCodeAt(char++) | 0; // bitwise or ensures we have a 32-bit int
886
+            }
887
+            return hash;
888
+        }
889
+
890
+        function attributeHash(elt) {
891
+            var hash = 0;
892
+            // IE fix
893
+            if (elt.attributes) {
894
+                for (var i = 0; i < elt.attributes.length; i++) {
895
+                    var attribute = elt.attributes[i];
896
+                    if(attribute.value){ // only include attributes w/ actual values (empty is same as non-existent)
897
+                        hash = stringHash(attribute.name, hash);
898
+                        hash = stringHash(attribute.value, hash);
899
+                    }
900
+                }
901
+            }
902
+            return hash;
903
+        }
904
+
905
+        function deInitNode(element) {
906
+            var internalData = getInternalData(element);
907
+            if (internalData.timeout) {
908
+                clearTimeout(internalData.timeout);
909
+            }
910
+            if (internalData.webSocket) {
911
+                internalData.webSocket.close();
912
+            }
913
+            if (internalData.sseEventSource) {
914
+                internalData.sseEventSource.close();
915
+            }
916
+            if (internalData.listenerInfos) {
917
+                forEach(internalData.listenerInfos, function (info) {
918
+                    if (info.on) {
919
+                        info.on.removeEventListener(info.trigger, info.listener);
920
+                    }
921
+                });
922
+            }
923
+            if (internalData.onHandlers) {
924
+                for (let i = 0; i < internalData.onHandlers.length; i++) {
925
+                    const handlerInfo = internalData.onHandlers[i];
926
+                    element.removeEventListener(handlerInfo.name, handlerInfo.handler);
927
+                }
928
+            }
929
+        }
930
+
931
+        function cleanUpElement(element) {
932
+            triggerEvent(element, "htmx:beforeCleanupElement")
933
+            deInitNode(element);
934
+            if (element.children) { // IE
935
+                forEach(element.children, function(child) { cleanUpElement(child) });
936
+            }
937
+        }
938
+
939
+        function swapOuterHTML(target, fragment, settleInfo) {
940
+            if (target.tagName === "BODY") {
941
+                return swapInnerHTML(target, fragment, settleInfo);
942
+            } else {
943
+                // @type {HTMLElement}
944
+                var newElt
945
+                var eltBeforeNewContent = target.previousSibling;
946
+                insertNodesBefore(parentElt(target), target, fragment, settleInfo);
947
+                if (eltBeforeNewContent == null) {
948
+                    newElt = parentElt(target).firstChild;
949
+                } else {
950
+                    newElt = eltBeforeNewContent.nextSibling;
951
+                }
952
+                getInternalData(target).replacedWith = newElt; // tuck away so we can fire events on it later
953
+                settleInfo.elts = [] // clear existing elements
954
+                while(newElt && newElt !== target) {
955
+                    if (newElt.nodeType === Node.ELEMENT_NODE) {
956
+                        settleInfo.elts.push(newElt);
957
+                    }
958
+                    newElt = newElt.nextElementSibling;
959
+                }
960
+                cleanUpElement(target);
961
+                parentElt(target).removeChild(target);
962
+            }
963
+        }
964
+
965
+        function swapAfterBegin(target, fragment, settleInfo) {
966
+            return insertNodesBefore(target, target.firstChild, fragment, settleInfo);
967
+        }
968
+
969
+        function swapBeforeBegin(target, fragment, settleInfo) {
970
+            return insertNodesBefore(parentElt(target), target, fragment, settleInfo);
971
+        }
972
+
973
+        function swapBeforeEnd(target, fragment, settleInfo) {
974
+            return insertNodesBefore(target, null, fragment, settleInfo);
975
+        }
976
+
977
+        function swapAfterEnd(target, fragment, settleInfo) {
978
+            return insertNodesBefore(parentElt(target), target.nextSibling, fragment, settleInfo);
979
+        }
980
+        function swapDelete(target, fragment, settleInfo) {
981
+            cleanUpElement(target);
982
+            return parentElt(target).removeChild(target);
983
+        }
984
+
985
+        function swapInnerHTML(target, fragment, settleInfo) {
986
+            var firstChild = target.firstChild;
987
+            insertNodesBefore(target, firstChild, fragment, settleInfo);
988
+            if (firstChild) {
989
+                while (firstChild.nextSibling) {
990
+                    cleanUpElement(firstChild.nextSibling)
991
+                    target.removeChild(firstChild.nextSibling);
992
+                }
993
+                cleanUpElement(firstChild)
994
+                target.removeChild(firstChild);
995
+            }
996
+        }
997
+
998
+        function maybeSelectFromResponse(elt, fragment) {
999
+            var selector = getClosestAttributeValue(elt, "hx-select");
1000
+            if (selector) {
1001
+                var newFragment = getDocument().createDocumentFragment();
1002
+                forEach(fragment.querySelectorAll(selector), function (node) {
1003
+                    newFragment.appendChild(node);
1004
+                });
1005
+                fragment = newFragment;
1006
+            }
1007
+            return fragment;
1008
+        }
1009
+
1010
+        function swap(swapStyle, elt, target, fragment, settleInfo) {
1011
+            switch (swapStyle) {
1012
+                case "none":
1013
+                    return;
1014
+                case "outerHTML":
1015
+                    swapOuterHTML(target, fragment, settleInfo);
1016
+                    return;
1017
+                case "afterbegin":
1018
+                    swapAfterBegin(target, fragment, settleInfo);
1019
+                    return;
1020
+                case "beforebegin":
1021
+                    swapBeforeBegin(target, fragment, settleInfo);
1022
+                    return;
1023
+                case "beforeend":
1024
+                    swapBeforeEnd(target, fragment, settleInfo);
1025
+                    return;
1026
+                case "afterend":
1027
+                    swapAfterEnd(target, fragment, settleInfo);
1028
+                    return;
1029
+                case "delete":
1030
+                    swapDelete(target, fragment, settleInfo);
1031
+                    return;
1032
+                default:
1033
+                    var extensions = getExtensions(elt);
1034
+                    for (var i = 0; i < extensions.length; i++) {
1035
+                        var ext = extensions[i];
1036
+                        try {
1037
+                            var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo);
1038
+                            if (newElements) {
1039
+                                if (typeof newElements.length !== 'undefined') {
1040
+                                    // if handleSwap returns an array (like) of elements, we handle them
1041
+                                    for (var j = 0; j < newElements.length; j++) {
1042
+                                        var child = newElements[j];
1043
+                                        if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) {
1044
+                                            settleInfo.tasks.push(makeAjaxLoadTask(child));
1045
+                                        }
1046
+                                    }
1047
+                                }
1048
+                                return;
1049
+                            }
1050
+                        } catch (e) {
1051
+                            logError(e);
1052
+                        }
1053
+                    }
1054
+                    if (swapStyle === "innerHTML") {
1055
+                        swapInnerHTML(target, fragment, settleInfo);
1056
+                    } else {
1057
+                        swap(htmx.config.defaultSwapStyle, elt, target, fragment, settleInfo);
1058
+                    }
1059
+            }
1060
+        }
1061
+
1062
+        function findTitle(content) {
1063
+            if (content.indexOf('<title') > -1) {
1064
+                var contentWithSvgsRemoved = content.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, '');
1065
+                var result = contentWithSvgsRemoved.match(/<title(\s[^>]*>|>)([\s\S]*?)<\/title>/im);
1066
+
1067
+                if (result) {
1068
+                    return result[2];
1069
+                }
1070
+            }
1071
+        }
1072
+
1073
+        function selectAndSwap(swapStyle, target, elt, responseText, settleInfo) {
1074
+            settleInfo.title = findTitle(responseText);
1075
+            var fragment = makeFragment(responseText);
1076
+            if (fragment) {
1077
+                handleOutOfBandSwaps(elt, fragment, settleInfo);
1078
+                fragment = maybeSelectFromResponse(elt, fragment);
1079
+                handlePreservedElements(fragment);
1080
+                return swap(swapStyle, elt, target, fragment, settleInfo);
1081
+            }
1082
+        }
1083
+
1084
+        function handleTrigger(xhr, header, elt) {
1085
+            var triggerBody = xhr.getResponseHeader(header);
1086
+            if (triggerBody.indexOf("{") === 0) {
1087
+                var triggers = parseJSON(triggerBody);
1088
+                for (var eventName in triggers) {
1089
+                    if (triggers.hasOwnProperty(eventName)) {
1090
+                        var detail = triggers[eventName];
1091
+                        if (!isRawObject(detail)) {
1092
+                            detail = {"value": detail}
1093
+                        }
1094
+                        triggerEvent(elt, eventName, detail);
1095
+                    }
1096
+                }
1097
+            } else {
1098
+                triggerEvent(elt, triggerBody, []);
1099
+            }
1100
+        }
1101
+
1102
+        var WHITESPACE = /\s/;
1103
+        var WHITESPACE_OR_COMMA = /[\s,]/;
1104
+        var SYMBOL_START = /[_$a-zA-Z]/;
1105
+        var SYMBOL_CONT = /[_$a-zA-Z0-9]/;
1106
+        var STRINGISH_START = ['"', "'", "/"];
1107
+        var NOT_WHITESPACE = /[^\s]/;
1108
+        function tokenizeString(str) {
1109
+            var tokens = [];
1110
+            var position = 0;
1111
+            while (position < str.length) {
1112
+                if(SYMBOL_START.exec(str.charAt(position))) {
1113
+                    var startPosition = position;
1114
+                    while (SYMBOL_CONT.exec(str.charAt(position + 1))) {
1115
+                        position++;
1116
+                    }
1117
+                    tokens.push(str.substr(startPosition, position - startPosition + 1));
1118
+                } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) {
1119
+                    var startChar = str.charAt(position);
1120
+                    var startPosition = position;
1121
+                    position++;
1122
+                    while (position < str.length && str.charAt(position) !== startChar ) {
1123
+                        if (str.charAt(position) === "\\") {
1124
+                            position++;
1125
+                        }
1126
+                        position++;
1127
+                    }
1128
+                    tokens.push(str.substr(startPosition, position - startPosition + 1));
1129
+                } else {
1130
+                    var symbol = str.charAt(position);
1131
+                    tokens.push(symbol);
1132
+                }
1133
+                position++;
1134
+            }
1135
+            return tokens;
1136
+        }
1137
+
1138
+        function isPossibleRelativeReference(token, last, paramName) {
1139
+            return SYMBOL_START.exec(token.charAt(0)) &&
1140
+                token !== "true" &&
1141
+                token !== "false" &&
1142
+                token !== "this" &&
1143
+                token !== paramName &&
1144
+                last !== ".";
1145
+        }
1146
+
1147
+        function maybeGenerateConditional(elt, tokens, paramName) {
1148
+            if (tokens[0] === '[') {
1149
+                tokens.shift();
1150
+                var bracketCount = 1;
1151
+                var conditionalSource = " return (function(" + paramName + "){ return (";
1152
+                var last = null;
1153
+                while (tokens.length > 0) {
1154
+                    var token = tokens[0];
1155
+                    if (token === "]") {
1156
+                        bracketCount--;
1157
+                        if (bracketCount === 0) {
1158
+                            if (last === null) {
1159
+                                conditionalSource = conditionalSource + "true";
1160
+                            }
1161
+                            tokens.shift();
1162
+                            conditionalSource += ")})";
1163
+                            try {
1164
+                                var conditionFunction = maybeEval(elt,function () {
1165
+                                    return Function(conditionalSource)();
1166
+                                    },
1167
+                                    function(){return true})
1168
+                                conditionFunction.source = conditionalSource;
1169
+                                return conditionFunction;
1170
+                            } catch (e) {
1171
+                                triggerErrorEvent(getDocument().body, "htmx:syntax:error", {error:e, source:conditionalSource})
1172
+                                return null;
1173
+                            }
1174
+                        }
1175
+                    } else if (token === "[") {
1176
+                        bracketCount++;
1177
+                    }
1178
+                    if (isPossibleRelativeReference(token, last, paramName)) {
1179
+                            conditionalSource += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))";
1180
+                    } else {
1181
+                        conditionalSource = conditionalSource + token;
1182
+                    }
1183
+                    last = tokens.shift();
1184
+                }
1185
+            }
1186
+        }
1187
+
1188
+        function consumeUntil(tokens, match) {
1189
+            var result = "";
1190
+            while (tokens.length > 0 && !tokens[0].match(match)) {
1191
+                result += tokens.shift();
1192
+            }
1193
+            return result;
1194
+        }
1195
+
1196
+        var INPUT_SELECTOR = 'input, textarea, select';
1197
+
1198
+        /**
1199
+         * @param {HTMLElement} elt
1200
+         * @returns {import("./htmx").HtmxTriggerSpecification[]}
1201
+         */
1202
+        function getTriggerSpecs(elt) {
1203
+            var explicitTrigger = getAttributeValue(elt, 'hx-trigger');
1204
+            var triggerSpecs = [];
1205
+            if (explicitTrigger) {
1206
+                var tokens = tokenizeString(explicitTrigger);
1207
+                do {
1208
+                    consumeUntil(tokens, NOT_WHITESPACE);
1209
+                    var initialLength = tokens.length;
1210
+                    var trigger = consumeUntil(tokens, /[,\[\s]/);
1211
+                    if (trigger !== "") {
1212
+                        if (trigger === "every") {
1213
+                            var every = {trigger: 'every'};
1214
+                            consumeUntil(tokens, NOT_WHITESPACE);
1215
+                            every.pollInterval = parseInterval(consumeUntil(tokens, /[,\[\s]/));
1216
+                            consumeUntil(tokens, NOT_WHITESPACE);
1217
+                            var eventFilter = maybeGenerateConditional(elt, tokens, "event");
1218
+                            if (eventFilter) {
1219
+                                every.eventFilter = eventFilter;
1220
+                            }
1221
+                            triggerSpecs.push(every);
1222
+                        } else if (trigger.indexOf("sse:") === 0) {
1223
+                            triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)});
1224
+                        } else {
1225
+                            var triggerSpec = {trigger: trigger};
1226
+                            var eventFilter = maybeGenerateConditional(elt, tokens, "event");
1227
+                            if (eventFilter) {
1228
+                                triggerSpec.eventFilter = eventFilter;
1229
+                            }
1230
+                            while (tokens.length > 0 && tokens[0] !== ",") {
1231
+                                consumeUntil(tokens, NOT_WHITESPACE)
1232
+                                var token = tokens.shift();
1233
+                                if (token === "changed") {
1234
+                                    triggerSpec.changed = true;
1235
+                                } else if (token === "once") {
1236
+                                    triggerSpec.once = true;
1237
+                                } else if (token === "consume") {
1238
+                                    triggerSpec.consume = true;
1239
+                                } else if (token === "delay" && tokens[0] === ":") {
1240
+                                    tokens.shift();
1241
+                                    triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA));
1242
+                                } else if (token === "from" && tokens[0] === ":") {
1243
+                                    tokens.shift();
1244
+                                    var from_arg = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1245
+                                    if (from_arg === "closest" || from_arg === "find" || from_arg === "next" || from_arg === "previous") {
1246
+                                        tokens.shift();
1247
+                                        from_arg +=
1248
+                                            " " +
1249
+                                            consumeUntil(
1250
+                                                tokens,
1251
+                                                WHITESPACE_OR_COMMA
1252
+                                            );
1253
+                                    }
1254
+                                    triggerSpec.from = from_arg;
1255
+                                } else if (token === "target" && tokens[0] === ":") {
1256
+                                    tokens.shift();
1257
+                                    triggerSpec.target = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1258
+                                } else if (token === "throttle" && tokens[0] === ":") {
1259
+                                    tokens.shift();
1260
+                                    triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE_OR_COMMA));
1261
+                                } else if (token === "queue" && tokens[0] === ":") {
1262
+                                    tokens.shift();
1263
+                                    triggerSpec.queue = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1264
+                                } else if ((token === "root" || token === "threshold") && tokens[0] === ":") {
1265
+                                    tokens.shift();
1266
+                                    triggerSpec[token] = consumeUntil(tokens, WHITESPACE_OR_COMMA);
1267
+                                } else {
1268
+                                    triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()});
1269
+                                }
1270
+                            }
1271
+                            triggerSpecs.push(triggerSpec);
1272
+                        }
1273
+                    }
1274
+                    if (tokens.length === initialLength) {
1275
+                        triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()});
1276
+                    }
1277
+                    consumeUntil(tokens, NOT_WHITESPACE);
1278
+                } while (tokens[0] === "," && tokens.shift())
1279
+            }
1280
+
1281
+            if (triggerSpecs.length > 0) {
1282
+                return triggerSpecs;
1283
+            } else if (matches(elt, 'form')) {
1284
+                return [{trigger: 'submit'}];
1285
+            } else if (matches(elt, 'input[type="button"]')){
1286
+                return [{trigger: 'click'}];
1287
+            } else if (matches(elt, INPUT_SELECTOR)) {
1288
+                return [{trigger: 'change'}];
1289
+            } else {
1290
+                return [{trigger: 'click'}];
1291
+            }
1292
+        }
1293
+
1294
+        function cancelPolling(elt) {
1295
+            getInternalData(elt).cancelled = true;
1296
+        }
1297
+
1298
+        function processPolling(elt, handler, spec) {
1299
+            var nodeData = getInternalData(elt);
1300
+            nodeData.timeout = setTimeout(function () {
1301
+                if (bodyContains(elt) && nodeData.cancelled !== true) {
1302
+                    if (!maybeFilterEvent(spec, makeEvent('hx:poll:trigger', {triggerSpec:spec, target:elt}))) {
1303
+                        handler(elt);
1304
+                    }
1305
+                    processPolling(elt, handler, spec);
1306
+                }
1307
+            }, spec.pollInterval);
1308
+        }
1309
+
1310
+        function isLocalLink(elt) {
1311
+            return location.hostname === elt.hostname &&
1312
+                getRawAttribute(elt,'href') &&
1313
+                getRawAttribute(elt,'href').indexOf("#") !== 0;
1314
+        }
1315
+
1316
+        function boostElement(elt, nodeData, triggerSpecs) {
1317
+            if ((elt.tagName === "A" && isLocalLink(elt) && (elt.target === "" || elt.target === "_self")) || elt.tagName === "FORM") {
1318
+                nodeData.boosted = true;
1319
+                var verb, path;
1320
+                if (elt.tagName === "A") {
1321
+                    verb = "get";
1322
+                    path = elt.href; // DOM property gives the fully resolved href of a relative link
1323
+                } else {
1324
+                    var rawAttribute = getRawAttribute(elt, "method");
1325
+                    verb = rawAttribute ? rawAttribute.toLowerCase() : "get";
1326
+                    if (verb === "get") {
1327
+                    }
1328
+                    path = getRawAttribute(elt, 'action');
1329
+                }
1330
+                triggerSpecs.forEach(function(triggerSpec) {
1331
+                    addEventListener(elt, function(elt, evt) {
1332
+                        issueAjaxRequest(verb, path, elt, evt)
1333
+                    }, nodeData, triggerSpec, true);
1334
+                });
1335
+            }
1336
+        }
1337
+
1338
+        /**
1339
+         *
1340
+         * @param {Event} evt
1341
+         * @param {HTMLElement} elt
1342
+         * @returns
1343
+         */
1344
+        function shouldCancel(evt, elt) {
1345
+            if (evt.type === "submit" || evt.type === "click") {
1346
+                if (elt.tagName === "FORM") {
1347
+                    return true;
1348
+                }
1349
+                if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) {
1350
+                    return true;
1351
+                }
1352
+                if (elt.tagName === "A" && elt.href &&
1353
+                    (elt.getAttribute('href') === '#' || elt.getAttribute('href').indexOf("#") !== 0)) {
1354
+                    return true;
1355
+                }
1356
+            }
1357
+            return false;
1358
+        }
1359
+
1360
+        function ignoreBoostedAnchorCtrlClick(elt, evt) {
1361
+            return getInternalData(elt).boosted && elt.tagName === "A" && evt.type === "click" && (evt.ctrlKey || evt.metaKey);
1362
+        }
1363
+
1364
+        function maybeFilterEvent(triggerSpec, evt) {
1365
+            var eventFilter = triggerSpec.eventFilter;
1366
+            if(eventFilter){
1367
+                try {
1368
+                    return eventFilter(evt) !== true;
1369
+                } catch(e) {
1370
+                    triggerErrorEvent(getDocument().body, "htmx:eventFilter:error", {error: e, source:eventFilter.source});
1371
+                    return true;
1372
+                }
1373
+            }
1374
+            return false;
1375
+        }
1376
+
1377
+        function addEventListener(elt, handler, nodeData, triggerSpec, explicitCancel) {
1378
+            var elementData = getInternalData(elt);
1379
+            var eltsToListenOn;
1380
+            if (triggerSpec.from) {
1381
+                eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from);
1382
+            } else {
1383
+                eltsToListenOn = [elt];
1384
+            }
1385
+            // store the initial value of the element so we can tell if it changes
1386
+            if (triggerSpec.changed) {
1387
+                elementData.lastValue = elt.value;
1388
+            }
1389
+            forEach(eltsToListenOn, function (eltToListenOn) {
1390
+                var eventListener = function (evt) {
1391
+                    if (!bodyContains(elt)) {
1392
+                        eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener);
1393
+                        return;
1394
+                    }
1395
+                    if (ignoreBoostedAnchorCtrlClick(elt, evt)) {
1396
+                        return;
1397
+                    }
1398
+                    if (explicitCancel || shouldCancel(evt, elt)) {
1399
+                        evt.preventDefault();
1400
+                    }
1401
+                    if (maybeFilterEvent(triggerSpec, evt)) {
1402
+                        return;
1403
+                    }
1404
+                    var eventData = getInternalData(evt);
1405
+                    eventData.triggerSpec = triggerSpec;
1406
+                    if (eventData.handledFor == null) {
1407
+                        eventData.handledFor = [];
1408
+                    }
1409
+                    if (eventData.handledFor.indexOf(elt) < 0) {
1410
+                        eventData.handledFor.push(elt);
1411
+                        if (triggerSpec.consume) {
1412
+                            evt.stopPropagation();
1413
+                        }
1414
+                        if (triggerSpec.target && evt.target) {
1415
+                            if (!matches(evt.target, triggerSpec.target)) {
1416
+                                return;
1417
+                            }
1418
+                        }
1419
+                        if (triggerSpec.once) {
1420
+                            if (elementData.triggeredOnce) {
1421
+                                return;
1422
+                            } else {
1423
+                                elementData.triggeredOnce = true;
1424
+                            }
1425
+                        }
1426
+                        if (triggerSpec.changed) {
1427
+                            if (elementData.lastValue === elt.value) {
1428
+                                return;
1429
+                            } else {
1430
+                                elementData.lastValue = elt.value;
1431
+                            }
1432
+                        }
1433
+                        if (elementData.delayed) {
1434
+                            clearTimeout(elementData.delayed);
1435
+                        }
1436
+                        if (elementData.throttle) {
1437
+                            return;
1438
+                        }
1439
+
1440
+                        if (triggerSpec.throttle) {
1441
+                            if (!elementData.throttle) {
1442
+                                handler(elt, evt);
1443
+                                elementData.throttle = setTimeout(function () {
1444
+                                    elementData.throttle = null;
1445
+                                }, triggerSpec.throttle);
1446
+                            }
1447
+                        } else if (triggerSpec.delay) {
1448
+                            elementData.delayed = setTimeout(function() { handler(elt, evt) }, triggerSpec.delay);
1449
+                        } else {
1450
+                            triggerEvent(elt, 'htmx:trigger')
1451
+                            handler(elt, evt);
1452
+                        }
1453
+                    }
1454
+                };
1455
+                if (nodeData.listenerInfos == null) {
1456
+                    nodeData.listenerInfos = [];
1457
+                }
1458
+                nodeData.listenerInfos.push({
1459
+                    trigger: triggerSpec.trigger,
1460
+                    listener: eventListener,
1461
+                    on: eltToListenOn
1462
+                })
1463
+                eltToListenOn.addEventListener(triggerSpec.trigger, eventListener);
1464
+            });
1465
+        }
1466
+
1467
+        var windowIsScrolling = false // used by initScrollHandler
1468
+        var scrollHandler = null;
1469
+        function initScrollHandler() {
1470
+            if (!scrollHandler) {
1471
+                scrollHandler = function() {
1472
+                    windowIsScrolling = true
1473
+                };
1474
+                window.addEventListener("scroll", scrollHandler)
1475
+                setInterval(function() {
1476
+                    if (windowIsScrolling) {
1477
+                        windowIsScrolling = false;
1478
+                        forEach(getDocument().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"), function (elt) {
1479
+                            maybeReveal(elt);
1480
+                        })
1481
+                    }
1482
+                }, 200);
1483
+            }
1484
+        }
1485
+
1486
+        function maybeReveal(elt) {
1487
+            if (!hasAttribute(elt,'data-hx-revealed') && isScrolledIntoView(elt)) {
1488
+                elt.setAttribute('data-hx-revealed', 'true');
1489
+                var nodeData = getInternalData(elt);
1490
+                if (nodeData.initHash) {
1491
+                    triggerEvent(elt, 'revealed');
1492
+                } else {
1493
+                    // if the node isn't initialized, wait for it before triggering the request
1494
+                    elt.addEventListener("htmx:afterProcessNode", function(evt) { triggerEvent(elt, 'revealed') }, {once: true});
1495
+                }
1496
+            }
1497
+        }
1498
+
1499
+        //====================================================================
1500
+        // Web Sockets
1501
+        //====================================================================
1502
+
1503
+        function processWebSocketInfo(elt, nodeData, info) {
1504
+            var values = splitOnWhitespace(info);
1505
+            for (var i = 0; i < values.length; i++) {
1506
+                var value = values[i].split(/:(.+)/);
1507
+                if (value[0] === "connect") {
1508
+                    ensureWebSocket(elt, value[1], 0);
1509
+                }
1510
+                if (value[0] === "send") {
1511
+                    processWebSocketSend(elt);
1512
+                }
1513
+            }
1514
+        }
1515
+
1516
+        function ensureWebSocket(elt, wssSource, retryCount) {
1517
+            if (!bodyContains(elt)) {
1518
+                return;  // stop ensuring websocket connection when socket bearing element ceases to exist
1519
+            }
1520
+
1521
+            if (wssSource.indexOf("/") == 0) {  // complete absolute paths only
1522
+                var base_part = location.hostname + (location.port ? ':'+location.port: '');
1523
+                if (location.protocol == 'https:') {
1524
+                    wssSource = "wss://" + base_part + wssSource;
1525
+                } else if (location.protocol == 'http:') {
1526
+                    wssSource = "ws://" + base_part + wssSource;
1527
+                }
1528
+            }
1529
+            var socket = htmx.createWebSocket(wssSource);
1530
+            socket.onerror = function (e) {
1531
+                triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket});
1532
+                maybeCloseWebSocketSource(elt);
1533
+            };
1534
+
1535
+            socket.onclose = function (e) {
1536
+                if ([1006, 1012, 1013].indexOf(e.code) >= 0) {  // Abnormal Closure/Service Restart/Try Again Later
1537
+                    var delay = getWebSocketReconnectDelay(retryCount);
1538
+                    setTimeout(function() {
1539
+                        ensureWebSocket(elt, wssSource, retryCount+1);  // creates a websocket with a new timeout
1540
+                    }, delay);
1541
+                }
1542
+            };
1543
+            socket.onopen = function (e) {
1544
+                retryCount = 0;
1545
+            }
1546
+
1547
+            getInternalData(elt).webSocket = socket;
1548
+            socket.addEventListener('message', function (event) {
1549
+                if (maybeCloseWebSocketSource(elt)) {
1550
+                    return;
1551
+                }
1552
+
1553
+                var response = event.data;
1554
+                withExtensions(elt, function(extension){
1555
+                    response = extension.transformResponse(response, null, elt);
1556
+                });
1557
+
1558
+                var settleInfo = makeSettleInfo(elt);
1559
+                var fragment = makeFragment(response);
1560
+                var children = toArray(fragment.children);
1561
+                for (var i = 0; i < children.length; i++) {
1562
+                    var child = children[i];
1563
+                    oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo);
1564
+                }
1565
+
1566
+                settleImmediately(settleInfo.tasks);
1567
+            });
1568
+        }
1569
+
1570
+        function maybeCloseWebSocketSource(elt) {
1571
+            if (!bodyContains(elt)) {
1572
+                getInternalData(elt).webSocket.close();
1573
+                return true;
1574
+            }
1575
+        }
1576
+
1577
+        function processWebSocketSend(elt) {
1578
+            var webSocketSourceElt = getClosestMatch(elt, function (parent) {
1579
+                return getInternalData(parent).webSocket != null;
1580
+            });
1581
+            if (webSocketSourceElt) {
1582
+                elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) {
1583
+                    var webSocket = getInternalData(webSocketSourceElt).webSocket;
1584
+                    var headers = getHeaders(elt, webSocketSourceElt);
1585
+                    var results = getInputValues(elt, 'post');
1586
+                    var errors = results.errors;
1587
+                    var rawParameters = results.values;
1588
+                    var expressionVars = getExpressionVars(elt);
1589
+                    var allParameters = mergeObjects(rawParameters, expressionVars);
1590
+                    var filteredParameters = filterValues(allParameters, elt);
1591
+                    filteredParameters['HEADERS'] = headers;
1592
+                    if (errors && errors.length > 0) {
1593
+                        triggerEvent(elt, 'htmx:validation:halted', errors);
1594
+                        return;
1595
+                    }
1596
+                    webSocket.send(JSON.stringify(filteredParameters));
1597
+                    if(shouldCancel(evt, elt)){
1598
+                        evt.preventDefault();
1599
+                    }
1600
+                });
1601
+            } else {
1602
+                triggerErrorEvent(elt, "htmx:noWebSocketSourceError");
1603
+            }
1604
+        }
1605
+
1606
+        function getWebSocketReconnectDelay(retryCount) {
1607
+            var delay = htmx.config.wsReconnectDelay;
1608
+            if (typeof delay === 'function') {
1609
+                // @ts-ignore
1610
+                return delay(retryCount);
1611
+            }
1612
+            if (delay === 'full-jitter') {
1613
+                var exp = Math.min(retryCount, 6);
1614
+                var maxDelay = 1000 * Math.pow(2, exp);
1615
+                return maxDelay * Math.random();
1616
+            }
1617
+            logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"');
1618
+        }
1619
+
1620
+        //====================================================================
1621
+        // Server Sent Events
1622
+        //====================================================================
1623
+
1624
+        function processSSEInfo(elt, nodeData, info) {
1625
+            var values = splitOnWhitespace(info);
1626
+            for (var i = 0; i < values.length; i++) {
1627
+                var value = values[i].split(/:(.+)/);
1628
+                if (value[0] === "connect") {
1629
+                    processSSESource(elt, value[1]);
1630
+                }
1631
+
1632
+                if ((value[0] === "swap")) {
1633
+                    processSSESwap(elt, value[1])
1634
+                }
1635
+            }
1636
+        }
1637
+
1638
+        function processSSESource(elt, sseSrc) {
1639
+            var source = htmx.createEventSource(sseSrc);
1640
+            source.onerror = function (e) {
1641
+                triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source});
1642
+                maybeCloseSSESource(elt);
1643
+            };
1644
+            getInternalData(elt).sseEventSource = source;
1645
+        }
1646
+
1647
+        function processSSESwap(elt, sseEventName) {
1648
+            var sseSourceElt = getClosestMatch(elt, hasEventSource);
1649
+            if (sseSourceElt) {
1650
+                var sseEventSource = getInternalData(sseSourceElt).sseEventSource;
1651
+                var sseListener = function (event) {
1652
+                    if (maybeCloseSSESource(sseSourceElt)) {
1653
+                        sseEventSource.removeEventListener(sseEventName, sseListener);
1654
+                        return;
1655
+                    }
1656
+
1657
+                    ///////////////////////////
1658
+                    // TODO: merge this code with AJAX and WebSockets code in the future.
1659
+
1660
+                    var response = event.data;
1661
+                    withExtensions(elt, function(extension){
1662
+                        response = extension.transformResponse(response, null, elt);
1663
+                    });
1664
+
1665
+                    var swapSpec = getSwapSpecification(elt)
1666
+                    var target = getTarget(elt)
1667
+                    var settleInfo = makeSettleInfo(elt);
1668
+
1669
+                    selectAndSwap(swapSpec.swapStyle, elt, target, response, settleInfo)
1670
+                    settleImmediately(settleInfo.tasks)
1671
+                    triggerEvent(elt, "htmx:sseMessage", event)
1672
+                };
1673
+
1674
+                getInternalData(elt).sseListener = sseListener;
1675
+                sseEventSource.addEventListener(sseEventName, sseListener);
1676
+            } else {
1677
+                triggerErrorEvent(elt, "htmx:noSSESourceError");
1678
+            }
1679
+        }
1680
+
1681
+        function processSSETrigger(elt, handler, sseEventName) {
1682
+            var sseSourceElt = getClosestMatch(elt, hasEventSource);
1683
+            if (sseSourceElt) {
1684
+                var sseEventSource = getInternalData(sseSourceElt).sseEventSource;
1685
+                var sseListener = function () {
1686
+                    if (!maybeCloseSSESource(sseSourceElt)) {
1687
+                        if (bodyContains(elt)) {
1688
+                            handler(elt);
1689
+                        } else {
1690
+                            sseEventSource.removeEventListener(sseEventName, sseListener);
1691
+                        }
1692
+                    }
1693
+                };
1694
+                getInternalData(elt).sseListener = sseListener;
1695
+                sseEventSource.addEventListener(sseEventName, sseListener);
1696
+            } else {
1697
+                triggerErrorEvent(elt, "htmx:noSSESourceError");
1698
+            }
1699
+        }
1700
+
1701
+        function maybeCloseSSESource(elt) {
1702
+            if (!bodyContains(elt)) {
1703
+                getInternalData(elt).sseEventSource.close();
1704
+                return true;
1705
+            }
1706
+        }
1707
+
1708
+        function hasEventSource(node) {
1709
+            return getInternalData(node).sseEventSource != null;
1710
+        }
1711
+
1712
+        //====================================================================
1713
+
1714
+        function loadImmediately(elt, handler, nodeData, delay) {
1715
+            var load = function(){
1716
+                if (!nodeData.loaded) {
1717
+                    nodeData.loaded = true;
1718
+                    handler(elt);
1719
+                }
1720
+            }
1721
+            if (delay) {
1722
+                setTimeout(load, delay);
1723
+            } else {
1724
+                load();
1725
+            }
1726
+        }
1727
+
1728
+        function processVerbs(elt, nodeData, triggerSpecs) {
1729
+            var explicitAction = false;
1730
+            forEach(VERBS, function (verb) {
1731
+                if (hasAttribute(elt,'hx-' + verb)) {
1732
+                    var path = getAttributeValue(elt, 'hx-' + verb);
1733
+                    explicitAction = true;
1734
+                    nodeData.path = path;
1735
+                    nodeData.verb = verb;
1736
+                    triggerSpecs.forEach(function(triggerSpec) {
1737
+                        addTriggerHandler(elt, triggerSpec, nodeData, function (elt, evt) {
1738
+                            issueAjaxRequest(verb, path, elt, evt)
1739
+                        })
1740
+                    });
1741
+                }
1742
+            });
1743
+            return explicitAction;
1744
+        }
1745
+
1746
+        function addTriggerHandler(elt, triggerSpec, nodeData, handler) {
1747
+            if (triggerSpec.sseEvent) {
1748
+                processSSETrigger(elt, handler, triggerSpec.sseEvent);
1749
+            } else if (triggerSpec.trigger === "revealed") {
1750
+                initScrollHandler();
1751
+                addEventListener(elt, handler, nodeData, triggerSpec);
1752
+                maybeReveal(elt);
1753
+            } else if (triggerSpec.trigger === "intersect") {
1754
+                var observerOptions = {};
1755
+                if (triggerSpec.root) {
1756
+                    observerOptions.root = querySelectorExt(elt, triggerSpec.root)
1757
+                }
1758
+                if (triggerSpec.threshold) {
1759
+                    observerOptions.threshold = parseFloat(triggerSpec.threshold);
1760
+                }
1761
+                var observer = new IntersectionObserver(function (entries) {
1762
+                    for (var i = 0; i < entries.length; i++) {
1763
+                        var entry = entries[i];
1764
+                        if (entry.isIntersecting) {
1765
+                            triggerEvent(elt, "intersect");
1766
+                            break;
1767
+                        }
1768
+                    }
1769
+                }, observerOptions);
1770
+                observer.observe(elt);
1771
+                addEventListener(elt, handler, nodeData, triggerSpec);
1772
+            } else if (triggerSpec.trigger === "load") {
1773
+                if (!maybeFilterEvent(triggerSpec, makeEvent("load", {elt:elt}))) {
1774
+                                loadImmediately(elt, handler, nodeData, triggerSpec.delay);
1775
+                            }
1776
+            } else if (triggerSpec.pollInterval) {
1777
+                nodeData.polling = true;
1778
+                processPolling(elt, handler, triggerSpec);
1779
+            } else {
1780
+                addEventListener(elt, handler, nodeData, triggerSpec);
1781
+            }
1782
+        }
1783
+
1784
+        function evalScript(script) {
1785
+            if (script.type === "text/javascript" || script.type === "module" || script.type === "") {
1786
+                var newScript = getDocument().createElement("script");
1787
+                forEach(script.attributes, function (attr) {
1788
+                    newScript.setAttribute(attr.name, attr.value);
1789
+                });
1790
+                newScript.textContent = script.textContent;
1791
+                newScript.async = false;
1792
+                if (htmx.config.inlineScriptNonce) {
1793
+                    newScript.nonce = htmx.config.inlineScriptNonce;
1794
+                }
1795
+                var parent = script.parentElement;
1796
+
1797
+                try {
1798
+                    parent.insertBefore(newScript, script);
1799
+                } catch (e) {
1800
+                    logError(e);
1801
+                } finally {
1802
+                    // remove old script element, but only if it is still in DOM
1803
+                    if (script.parentElement) {
1804
+                        script.parentElement.removeChild(script);
1805
+                    }
1806
+                }
1807
+            }
1808
+        }
1809
+
1810
+        function processScripts(elt) {
1811
+            if (matches(elt, "script")) {
1812
+                evalScript(elt);
1813
+            }
1814
+            forEach(findAll(elt, "script"), function (script) {
1815
+                evalScript(script);
1816
+            });
1817
+        }
1818
+
1819
+        function hasChanceOfBeingBoosted() {
1820
+            return document.querySelector("[hx-boost], [data-hx-boost]");
1821
+        }
1822
+
1823
+        function findElementsToProcess(elt) {
1824
+            if (elt.querySelectorAll) {
1825
+                var boostedElts = hasChanceOfBeingBoosted() ? ", a, form" : "";
1826
+                var results = elt.querySelectorAll(VERB_SELECTOR + boostedElts + ", [hx-sse], [data-hx-sse], [hx-ws]," +
1827
+                    " [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger], [hx-on], [data-hx-on]");
1828
+                return results;
1829
+            } else {
1830
+                return [];
1831
+            }
1832
+        }
1833
+
1834
+        function initButtonTracking(form){
1835
+            var maybeSetLastButtonClicked = function(evt){
1836
+                var elt = closest(evt.target, "button, input[type='submit']");
1837
+                if (elt !== null) {
1838
+                    var internalData = getInternalData(form);
1839
+                    internalData.lastButtonClicked = elt;
1840
+                }
1841
+            };
1842
+
1843
+            // need to handle both click and focus in:
1844
+            //   focusin - in case someone tabs in to a button and hits the space bar
1845
+            //   click - on OSX buttons do not focus on click see https://bugs.webkit.org/show_bug.cgi?id=13724
1846
+
1847
+            form.addEventListener('click', maybeSetLastButtonClicked)
1848
+            form.addEventListener('focusin', maybeSetLastButtonClicked)
1849
+            form.addEventListener('focusout', function(evt){
1850
+                var internalData = getInternalData(form);
1851
+                internalData.lastButtonClicked = null;
1852
+            })
1853
+        }
1854
+
1855
+        function countCurlies(line) {
1856
+            var tokens = tokenizeString(line);
1857
+            var netCurlies = 0;
1858
+            for (let i = 0; i < tokens.length; i++) {
1859
+                const token = tokens[i];
1860
+                if (token === "{") {
1861
+                    netCurlies++;
1862
+                } else if (token === "}") {
1863
+                    netCurlies--;
1864
+                }
1865
+            }
1866
+            return netCurlies;
1867
+        }
1868
+
1869
+        function addHxOnEventHandler(elt, eventName, code) {
1870
+            var nodeData = getInternalData(elt);
1871
+            nodeData.onHandlers = [];
1872
+            var func = new Function("event", code + "; return;");
1873
+            var listener = elt.addEventListener(eventName, function (e) {
1874
+                return func.call(elt, e);
1875
+            });
1876
+            nodeData.onHandlers.push({event:eventName, listener:listener});
1877
+            return {nodeData, code, func, listener};
1878
+        }
1879
+
1880
+        function processHxOn(elt) {
1881
+            var hxOnValue = getAttributeValue(elt, 'hx-on');
1882
+            if (hxOnValue) {
1883
+                var handlers = {}
1884
+                var lines = hxOnValue.split("\n");
1885
+                var currentEvent = null;
1886
+                var curlyCount = 0;
1887
+                while (lines.length > 0) {
1888
+                    var line = lines.shift();
1889
+                    var match = line.match(/^\s*([a-zA-Z:\-]+:)(.*)/);
1890
+                    if (curlyCount === 0 && match) {
1891
+                        line.split(":")
1892
+                        currentEvent = match[1].slice(0, -1); // strip last colon
1893
+                        handlers[currentEvent] = match[2];
1894
+                    } else {
1895
+                        handlers[currentEvent] += line;
1896
+                    }
1897
+                    curlyCount += countCurlies(line);
1898
+                }
1899
+
1900
+                for (var eventName in handlers) {
1901
+                    addHxOnEventHandler(elt, eventName, handlers[eventName]);
1902
+                }
1903
+            }
1904
+        }
1905
+
1906
+        function initNode(elt) {
1907
+            if (elt.closest && elt.closest(htmx.config.disableSelector)) {
1908
+                return;
1909
+            }
1910
+            var nodeData = getInternalData(elt);
1911
+            if (nodeData.initHash !== attributeHash(elt)) {
1912
+
1913
+                nodeData.initHash = attributeHash(elt);
1914
+
1915
+                // clean up any previously processed info
1916
+                deInitNode(elt);
1917
+
1918
+                processHxOn(elt);
1919
+
1920
+                triggerEvent(elt, "htmx:beforeProcessNode")
1921
+
1922
+                if (elt.value) {
1923
+                    nodeData.lastValue = elt.value;
1924
+                }
1925
+
1926
+                var triggerSpecs = getTriggerSpecs(elt);
1927
+                var hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs);
1928
+
1929
+                if (!hasExplicitHttpAction) {
1930
+                    if (getClosestAttributeValue(elt, "hx-boost") === "true") {
1931
+                        boostElement(elt, nodeData, triggerSpecs);
1932
+                    } else if (hasAttribute(elt, 'hx-trigger')) {
1933
+                        triggerSpecs.forEach(function (triggerSpec) {
1934
+                            // For "naked" triggers, don't do anything at all
1935
+                            addTriggerHandler(elt, triggerSpec, nodeData, function () {
1936
+                            })
1937
+                        })
1938
+                    }
1939
+                }
1940
+
1941
+                if (elt.tagName === "FORM") {
1942
+                    initButtonTracking(elt);
1943
+                }
1944
+
1945
+                var sseInfo = getAttributeValue(elt, 'hx-sse');
1946
+                if (sseInfo) {
1947
+                    processSSEInfo(elt, nodeData, sseInfo);
1948
+                }
1949
+
1950
+                var wsInfo = getAttributeValue(elt, 'hx-ws');
1951
+                if (wsInfo) {
1952
+                    processWebSocketInfo(elt, nodeData, wsInfo);
1953
+                }
1954
+                triggerEvent(elt, "htmx:afterProcessNode");
1955
+            }
1956
+        }
1957
+
1958
+        function processNode(elt) {
1959
+            elt = resolveTarget(elt);
1960
+            initNode(elt);
1961
+            forEach(findElementsToProcess(elt), function(child) { initNode(child) });
1962
+        }
1963
+
1964
+        //====================================================================
1965
+        // Event/Log Support
1966
+        //====================================================================
1967
+
1968
+        function kebabEventName(str) {
1969
+            return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
1970
+        }
1971
+
1972
+        function makeEvent(eventName, detail) {
1973
+            var evt;
1974
+            if (window.CustomEvent && typeof window.CustomEvent === 'function') {
1975
+                evt = new CustomEvent(eventName, {bubbles: true, cancelable: true, detail: detail});
1976
+            } else {
1977
+                evt = getDocument().createEvent('CustomEvent');
1978
+                evt.initCustomEvent(eventName, true, true, detail);
1979
+            }
1980
+            return evt;
1981
+        }
1982
+
1983
+        function triggerErrorEvent(elt, eventName, detail) {
1984
+            triggerEvent(elt, eventName, mergeObjects({error:eventName}, detail));
1985
+        }
1986
+
1987
+        function ignoreEventForLogging(eventName) {
1988
+            return eventName === "htmx:afterProcessNode"
1989
+        }
1990
+
1991
+        /**
1992
+         * `withExtensions` locates all active extensions for a provided element, then
1993
+         * executes the provided function using each of the active extensions.  It should
1994
+         * be called internally at every extendable execution point in htmx.
1995
+         *
1996
+         * @param {HTMLElement} elt
1997
+         * @param {(extension:import("./htmx").HtmxExtension) => void} toDo
1998
+         * @returns void
1999
+         */
2000
+        function withExtensions(elt, toDo) {
2001
+            forEach(getExtensions(elt), function(extension){
2002
+                try {
2003
+                    toDo(extension);
2004
+                } catch (e) {
2005
+                    logError(e);
2006
+                }
2007
+            });
2008
+        }
2009
+
2010
+        function logError(msg) {
2011
+            if(console.error) {
2012
+                console.error(msg);
2013
+            } else if (console.log) {
2014
+                console.log("ERROR: ", msg);
2015
+            }
2016
+        }
2017
+
2018
+        function triggerEvent(elt, eventName, detail) {
2019
+            elt = resolveTarget(elt);
2020
+            if (detail == null) {
2021
+                detail = {};
2022
+            }
2023
+            detail["elt"] = elt;
2024
+            var event = makeEvent(eventName, detail);
2025
+            if (htmx.logger && !ignoreEventForLogging(eventName)) {
2026
+                htmx.logger(elt, eventName, detail);
2027
+            }
2028
+            if (detail.error) {
2029
+                logError(detail.error);
2030
+                triggerEvent(elt, "htmx:error", {errorInfo:detail})
2031
+            }
2032
+            var eventResult = elt.dispatchEvent(event);
2033
+            var kebabName = kebabEventName(eventName);
2034
+            if (eventResult && kebabName !== eventName) {
2035
+                var kebabedEvent = makeEvent(kebabName, event.detail);
2036
+                eventResult = eventResult && elt.dispatchEvent(kebabedEvent)
2037
+            }
2038
+            withExtensions(elt, function (extension) {
2039
+                eventResult = eventResult && (extension.onEvent(eventName, event) !== false)
2040
+            });
2041
+            return eventResult;
2042
+        }
2043
+
2044
+        //====================================================================
2045
+        // History Support
2046
+        //====================================================================
2047
+        var currentPathForHistory = location.pathname+location.search;
2048
+
2049
+        function getHistoryElement() {
2050
+            var historyElt = getDocument().querySelector('[hx-history-elt],[data-hx-history-elt]');
2051
+            return historyElt || getDocument().body;
2052
+        }
2053
+
2054
+        function saveToHistoryCache(url, content, title, scroll) {
2055
+            if (!canAccessLocalStorage()) {
2056
+                return;
2057
+            }
2058
+
2059
+            url = normalizePath(url);
2060
+
2061
+            var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || [];
2062
+            for (var i = 0; i < historyCache.length; i++) {
2063
+                if (historyCache[i].url === url) {
2064
+                    historyCache.splice(i, 1);
2065
+                    break;
2066
+                }
2067
+            }
2068
+            var newHistoryItem = {url:url, content: content, title:title, scroll:scroll};
2069
+            triggerEvent(getDocument().body, "htmx:historyItemCreated", {item:newHistoryItem, cache: historyCache})
2070
+            historyCache.push(newHistoryItem)
2071
+            while (historyCache.length > htmx.config.historyCacheSize) {
2072
+                historyCache.shift();
2073
+            }
2074
+            while(historyCache.length > 0){
2075
+                try {
2076
+                    localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache));
2077
+                    break;
2078
+                } catch (e) {
2079
+                    triggerErrorEvent(getDocument().body, "htmx:historyCacheError", {cause:e, cache: historyCache})
2080
+                    historyCache.shift(); // shrink the cache and retry
2081
+                }
2082
+            }
2083
+        }
2084
+
2085
+        function getCachedHistory(url) {
2086
+            if (!canAccessLocalStorage()) {
2087
+                return null;
2088
+            }
2089
+
2090
+            url = normalizePath(url);
2091
+
2092
+            var historyCache = parseJSON(localStorage.getItem("htmx-history-cache")) || [];
2093
+            for (var i = 0; i < historyCache.length; i++) {
2094
+                if (historyCache[i].url === url) {
2095
+                    return historyCache[i];
2096
+                }
2097
+            }
2098
+            return null;
2099
+        }
2100
+
2101
+        function cleanInnerHtmlForHistory(elt) {
2102
+            var className = htmx.config.requestClass;
2103
+            var clone = elt.cloneNode(true);
2104
+            forEach(findAll(clone, "." + className), function(child){
2105
+                removeClassFromElement(child, className);
2106
+            });
2107
+            return clone.innerHTML;
2108
+        }
2109
+
2110
+        function saveCurrentPageToHistory() {
2111
+            var elt = getHistoryElement();
2112
+            var path = currentPathForHistory || location.pathname+location.search;
2113
+
2114
+            // Allow history snapshot feature to be disabled where hx-history="false"
2115
+            // is present *anywhere* in the current document we're about to save,
2116
+            // so we can prevent privileged data entering the cache.
2117
+            // The page will still be reachable as a history entry, but htmx will fetch it
2118
+            // live from the server onpopstate rather than look in the localStorage cache
2119
+            var disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]');
2120
+            if (!disableHistoryCache) {
2121
+                triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path: path, historyElt: elt});
2122
+                saveToHistoryCache(path, cleanInnerHtmlForHistory(elt), getDocument().title, window.scrollY);
2123
+            }
2124
+
2125
+            if (htmx.config.historyEnabled) history.replaceState({htmx: true}, getDocument().title, window.location.href);
2126
+        }
2127
+
2128
+        function pushUrlIntoHistory(path) {
2129
+            // remove the cache buster parameter, if any
2130
+            if (htmx.config.getCacheBusterParam) {
2131
+                path = path.replace(/org\.htmx\.cache-buster=[^&]*&?/, '')
2132
+                if (path.endsWith('&') || path.endsWith("?")) {
2133
+                    path = path.slice(0, -1);
2134
+                }
2135
+            }
2136
+            if(htmx.config.historyEnabled) {
2137
+                history.pushState({htmx:true}, "", path);
2138
+            }
2139
+            currentPathForHistory = path;
2140
+        }
2141
+
2142
+        function replaceUrlInHistory(path) {
2143
+            if(htmx.config.historyEnabled)  history.replaceState({htmx:true}, "", path);
2144
+            currentPathForHistory = path;
2145
+        }
2146
+
2147
+        function settleImmediately(tasks) {
2148
+            forEach(tasks, function (task) {
2149
+                task.call();
2150
+            });
2151
+        }
2152
+
2153
+        function loadHistoryFromServer(path) {
2154
+            var request = new XMLHttpRequest();
2155
+            var details = {path: path, xhr:request};
2156
+            triggerEvent(getDocument().body, "htmx:historyCacheMiss", details);
2157
+            request.open('GET', path, true);
2158
+            request.setRequestHeader("HX-History-Restore-Request", "true");
2159
+            request.onload = function () {
2160
+                if (this.status >= 200 && this.status < 400) {
2161
+                    triggerEvent(getDocument().body, "htmx:historyCacheMissLoad", details);
2162
+                    var fragment = makeFragment(this.response);
2163
+                    // @ts-ignore
2164
+                    fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment;
2165
+                    var historyElement = getHistoryElement();
2166
+                    var settleInfo = makeSettleInfo(historyElement);
2167
+                    var title = findTitle(this.response);
2168
+                    if (title) {
2169
+                        var titleElt = find("title");
2170
+                        if (titleElt) {
2171
+                            titleElt.innerHTML = title;
2172
+                        } else {
2173
+                            window.document.title = title;
2174
+                        }
2175
+                    }
2176
+                    // @ts-ignore
2177
+                    swapInnerHTML(historyElement, fragment, settleInfo)
2178
+                    settleImmediately(settleInfo.tasks);
2179
+                    currentPathForHistory = path;
2180
+                    triggerEvent(getDocument().body, "htmx:historyRestore", {path: path, cacheMiss:true, serverResponse:this.response});
2181
+                } else {
2182
+                    triggerErrorEvent(getDocument().body, "htmx:historyCacheMissLoadError", details);
2183
+                }
2184
+            };
2185
+            request.send();
2186
+        }
2187
+
2188
+        function restoreHistory(path) {
2189
+            saveCurrentPageToHistory();
2190
+            path = path || location.pathname+location.search;
2191
+            var cached = getCachedHistory(path);
2192
+            if (cached) {
2193
+                var fragment = makeFragment(cached.content);
2194
+                var historyElement = getHistoryElement();
2195
+                var settleInfo = makeSettleInfo(historyElement);
2196
+                swapInnerHTML(historyElement, fragment, settleInfo)
2197
+                settleImmediately(settleInfo.tasks);
2198
+                document.title = cached.title;
2199
+                window.scrollTo(0, cached.scroll);
2200
+                currentPathForHistory = path;
2201
+                triggerEvent(getDocument().body, "htmx:historyRestore", {path:path, item:cached});
2202
+            } else {
2203
+                if (htmx.config.refreshOnHistoryMiss) {
2204
+
2205
+                    // @ts-ignore: optional parameter in reload() function throws error
2206
+                    window.location.reload(true);
2207
+                } else {
2208
+                    loadHistoryFromServer(path);
2209
+                }
2210
+            }
2211
+        }
2212
+
2213
+        function addRequestIndicatorClasses(elt) {
2214
+            var indicators = findAttributeTargets(elt, 'hx-indicator');
2215
+            if (indicators == null) {
2216
+                indicators = [elt];
2217
+            }
2218
+            forEach(indicators, function (ic) {
2219
+                var internalData = getInternalData(ic);
2220
+                internalData.requestCount = (internalData.requestCount || 0) + 1;
2221
+                ic.classList["add"].call(ic.classList, htmx.config.requestClass);
2222
+            });
2223
+            return indicators;
2224
+        }
2225
+
2226
+        function removeRequestIndicatorClasses(indicators) {
2227
+            forEach(indicators, function (ic) {
2228
+                var internalData = getInternalData(ic);
2229
+                internalData.requestCount = (internalData.requestCount || 0) - 1;
2230
+                if (internalData.requestCount === 0) {
2231
+                    ic.classList["remove"].call(ic.classList, htmx.config.requestClass);
2232
+                }
2233
+            });
2234
+        }
2235
+
2236
+        //====================================================================
2237
+        // Input Value Processing
2238
+        //====================================================================
2239
+
2240
+        function haveSeenNode(processed, elt) {
2241
+            for (var i = 0; i < processed.length; i++) {
2242
+                var node = processed[i];
2243
+                if (node.isSameNode(elt)) {
2244
+                    return true;
2245
+                }
2246
+            }
2247
+            return false;
2248
+        }
2249
+
2250
+        function shouldInclude(elt) {
2251
+            if(elt.name === "" || elt.name == null || elt.disabled) {
2252
+                return false;
2253
+            }
2254
+            // ignore "submitter" types (see jQuery src/serialize.js)
2255
+            if (elt.type === "button" || elt.type === "submit" || elt.tagName === "image" || elt.tagName === "reset" || elt.tagName === "file" ) {
2256
+                return false;
2257
+            }
2258
+            if (elt.type === "checkbox" || elt.type === "radio" ) {
2259
+                return elt.checked;
2260
+            }
2261
+            return true;
2262
+        }
2263
+
2264
+        function processInputValue(processed, values, errors, elt, validate) {
2265
+            if (elt == null || haveSeenNode(processed, elt)) {
2266
+                return;
2267
+            } else {
2268
+                processed.push(elt);
2269
+            }
2270
+            if (shouldInclude(elt)) {
2271
+                var name = getRawAttribute(elt,"name");
2272
+                var value = elt.value;
2273
+                if (elt.multiple) {
2274
+                    value = toArray(elt.querySelectorAll("option:checked")).map(function (e) { return e.value });
2275
+                }
2276
+                // include file inputs
2277
+                if (elt.files) {
2278
+                    value = toArray(elt.files);
2279
+                }
2280
+                // This is a little ugly because both the current value of the named value in the form
2281
+                // and the new value could be arrays, so we have to handle all four cases :/
2282
+                if (name != null && value != null) {
2283
+                    var current = values[name];
2284
+                    if (current !== undefined) {
2285
+                        if (Array.isArray(current)) {
2286
+                            if (Array.isArray(value)) {
2287
+                                values[name] = current.concat(value);
2288
+                            } else {
2289
+                                current.push(value);
2290
+                            }
2291
+                        } else {
2292
+                            if (Array.isArray(value)) {
2293
+                                values[name] = [current].concat(value);
2294
+                            } else {
2295
+                                values[name] = [current, value];
2296
+                            }
2297
+                        }
2298
+                    } else {
2299
+                        values[name] = value;
2300
+                    }
2301
+                }
2302
+                if (validate) {
2303
+                    validateElement(elt, errors);
2304
+                }
2305
+            }
2306
+            if (matches(elt, 'form')) {
2307
+                var inputs = elt.elements;
2308
+                forEach(inputs, function(input) {
2309
+                    processInputValue(processed, values, errors, input, validate);
2310
+                });
2311
+            }
2312
+        }
2313
+
2314
+        function validateElement(element, errors) {
2315
+            if (element.willValidate) {
2316
+                triggerEvent(element, "htmx:validation:validate")
2317
+                if (!element.checkValidity()) {
2318
+                    errors.push({elt: element, message:element.validationMessage, validity:element.validity});
2319
+                    triggerEvent(element, "htmx:validation:failed", {message:element.validationMessage, validity:element.validity})
2320
+                }
2321
+            }
2322
+        }
2323
+
2324
+        /**
2325
+         * @param {HTMLElement} elt
2326
+         * @param {string} verb
2327
+         */
2328
+        function getInputValues(elt, verb) {
2329
+            var processed = [];
2330
+            var values = {};
2331
+            var formValues = {};
2332
+            var errors = [];
2333
+            var internalData = getInternalData(elt);
2334
+
2335
+            // only validate when form is directly submitted and novalidate or formnovalidate are not set
2336
+            // or if the element has an explicit hx-validate="true" on it
2337
+            var validate = (matches(elt, 'form') && elt.noValidate !== true) || getAttributeValue(elt, "hx-validate") === "true";
2338
+            if (internalData.lastButtonClicked) {
2339
+                validate = validate && internalData.lastButtonClicked.formNoValidate !== true;
2340
+            }
2341
+
2342
+            // for a non-GET include the closest form
2343
+            if (verb !== 'get') {
2344
+                processInputValue(processed, formValues, errors, closest(elt, 'form'), validate);
2345
+            }
2346
+
2347
+            // include the element itself
2348
+            processInputValue(processed, values, errors, elt, validate);
2349
+
2350
+            // if a button or submit was clicked last, include its value
2351
+            if (internalData.lastButtonClicked) {
2352
+                var name = getRawAttribute(internalData.lastButtonClicked,"name");
2353
+                if (name) {
2354
+                    values[name] = internalData.lastButtonClicked.value;
2355
+                }
2356
+            }
2357
+
2358
+            // include any explicit includes
2359
+            var includes = findAttributeTargets(elt, "hx-include");
2360
+            forEach(includes, function(node) {
2361
+                processInputValue(processed, values, errors, node, validate);
2362
+                // if a non-form is included, include any input values within it
2363
+                if (!matches(node, 'form')) {
2364
+                    forEach(node.querySelectorAll(INPUT_SELECTOR), function (descendant) {
2365
+                        processInputValue(processed, values, errors, descendant, validate);
2366
+                    })
2367
+                }
2368
+            });
2369
+
2370
+            // form values take precedence, overriding the regular values
2371
+            values = mergeObjects(values, formValues);
2372
+
2373
+            return {errors:errors, values:values};
2374
+        }
2375
+
2376
+        function appendParam(returnStr, name, realValue) {
2377
+            if (returnStr !== "") {
2378
+                returnStr += "&";
2379
+            }
2380
+            if (String(realValue) === "[object Object]") {
2381
+                realValue = JSON.stringify(realValue);
2382
+            }
2383
+            var s = encodeURIComponent(realValue);
2384
+            returnStr += encodeURIComponent(name) + "=" + s;
2385
+            return returnStr;
2386
+        }
2387
+
2388
+        function urlEncode(values) {
2389
+            var returnStr = "";
2390
+            for (var name in values) {
2391
+                if (values.hasOwnProperty(name)) {
2392
+                    var value = values[name];
2393
+                    if (Array.isArray(value)) {
2394
+                        forEach(value, function(v) {
2395
+                            returnStr = appendParam(returnStr, name, v);
2396
+                        });
2397
+                    } else {
2398
+                        returnStr = appendParam(returnStr, name, value);
2399
+                    }
2400
+                }
2401
+            }
2402
+            return returnStr;
2403
+        }
2404
+
2405
+        function makeFormData(values) {
2406
+            var formData = new FormData();
2407
+            for (var name in values) {
2408
+                if (values.hasOwnProperty(name)) {
2409
+                    var value = values[name];
2410
+                    if (Array.isArray(value)) {
2411
+                        forEach(value, function(v) {
2412
+                            formData.append(name, v);
2413
+                        });
2414
+                    } else {
2415
+                        formData.append(name, value);
2416
+                    }
2417
+                }
2418
+            }
2419
+            return formData;
2420
+        }
2421
+
2422
+        //====================================================================
2423
+        // Ajax
2424
+        //====================================================================
2425
+
2426
+        /**
2427
+         * @param {HTMLElement} elt
2428
+         * @param {HTMLElement} target
2429
+         * @param {string} prompt
2430
+         * @returns {Object} // TODO: Define/Improve HtmxHeaderSpecification
2431
+         */
2432
+        function getHeaders(elt, target, prompt) {
2433
+            var headers = {
2434
+                "HX-Request" : "true",
2435
+                "HX-Trigger" : getRawAttribute(elt, "id"),
2436
+                "HX-Trigger-Name" : getRawAttribute(elt, "name"),
2437
+                "HX-Target" : getAttributeValue(target, "id"),
2438
+                "HX-Current-URL" : getDocument().location.href,
2439
+            }
2440
+            getValuesForElement(elt, "hx-headers", false, headers)
2441
+            if (prompt !== undefined) {
2442
+                headers["HX-Prompt"] = prompt;
2443
+            }
2444
+            if (getInternalData(elt).boosted) {
2445
+                headers["HX-Boosted"] = "true";
2446
+            }
2447
+            return headers;
2448
+        }
2449
+
2450
+        /**
2451
+         * filterValues takes an object containing form input values
2452
+         * and returns a new object that only contains keys that are
2453
+         * specified by the closest "hx-params" attribute
2454
+         * @param {Object} inputValues
2455
+         * @param {HTMLElement} elt
2456
+         * @returns {Object}
2457
+         */
2458
+        function filterValues(inputValues, elt) {
2459
+            var paramsValue = getClosestAttributeValue(elt, "hx-params");
2460
+            if (paramsValue) {
2461
+                if (paramsValue === "none") {
2462
+                    return {};
2463
+                } else if (paramsValue === "*") {
2464
+                    return inputValues;
2465
+                } else if(paramsValue.indexOf("not ") === 0) {
2466
+                    forEach(paramsValue.substr(4).split(","), function (name) {
2467
+                        name = name.trim();
2468
+                        delete inputValues[name];
2469
+                    });
2470
+                    return inputValues;
2471
+                } else {
2472
+                    var newValues = {}
2473
+                    forEach(paramsValue.split(","), function (name) {
2474
+                        name = name.trim();
2475
+                        newValues[name] = inputValues[name];
2476
+                    });
2477
+                    return newValues;
2478
+                }
2479
+            } else {
2480
+                return inputValues;
2481
+            }
2482
+        }
2483
+
2484
+        function isAnchorLink(elt) {
2485
+          return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0
2486
+        }
2487
+
2488
+        /**
2489
+         *
2490
+         * @param {HTMLElement} elt
2491
+         * @param {string} swapInfoOverride
2492
+         * @returns {import("./htmx").HtmxSwapSpecification}
2493
+         */
2494
+        function getSwapSpecification(elt, swapInfoOverride) {
2495
+            var swapInfo = swapInfoOverride ? swapInfoOverride : getClosestAttributeValue(elt, "hx-swap");
2496
+            var swapSpec = {
2497
+                "swapStyle" : getInternalData(elt).boosted ? 'innerHTML' : htmx.config.defaultSwapStyle,
2498
+                "swapDelay" : htmx.config.defaultSwapDelay,
2499
+                "settleDelay" : htmx.config.defaultSettleDelay
2500
+            }
2501
+            if (getInternalData(elt).boosted && !isAnchorLink(elt)) {
2502
+              swapSpec["show"] = "top"
2503
+            }
2504
+            if (swapInfo) {
2505
+                var split = splitOnWhitespace(swapInfo);
2506
+                if (split.length > 0) {
2507
+                    swapSpec["swapStyle"] = split[0];
2508
+                    for (var i = 1; i < split.length; i++) {
2509
+                        var modifier = split[i];
2510
+                        if (modifier.indexOf("swap:") === 0) {
2511
+                            swapSpec["swapDelay"] = parseInterval(modifier.substr(5));
2512
+                        }
2513
+                        if (modifier.indexOf("settle:") === 0) {
2514
+                            swapSpec["settleDelay"] = parseInterval(modifier.substr(7));
2515
+                        }
2516
+                        if (modifier.indexOf("transition:") === 0) {
2517
+                            swapSpec["transition"] = modifier.substr(11) === "true";
2518
+                        }
2519
+                        if (modifier.indexOf("scroll:") === 0) {
2520
+                            var scrollSpec = modifier.substr(7);
2521
+                            var splitSpec = scrollSpec.split(":");
2522
+                            var scrollVal = splitSpec.pop();
2523
+                            var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null;
2524
+                            swapSpec["scroll"] = scrollVal;
2525
+                            swapSpec["scrollTarget"] = selectorVal;
2526
+                        }
2527
+                        if (modifier.indexOf("show:") === 0) {
2528
+                            var showSpec = modifier.substr(5);
2529
+                            var splitSpec = showSpec.split(":");
2530
+                            var showVal = splitSpec.pop();
2531
+                            var selectorVal = splitSpec.length > 0 ? splitSpec.join(":") : null;
2532
+                            swapSpec["show"] = showVal;
2533
+                            swapSpec["showTarget"] = selectorVal;
2534
+                        }
2535
+                        if (modifier.indexOf("focus-scroll:") === 0) {
2536
+                            var focusScrollVal = modifier.substr("focus-scroll:".length);
2537
+                            swapSpec["focusScroll"] = focusScrollVal == "true";
2538
+                        }
2539
+                    }
2540
+                }
2541
+            }
2542
+            return swapSpec;
2543
+        }
2544
+
2545
+        function usesFormData(elt) {
2546
+            return getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" ||
2547
+                (matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data");
2548
+        }
2549
+
2550
+        function encodeParamsForBody(xhr, elt, filteredParameters) {
2551
+            var encodedParameters = null;
2552
+            withExtensions(elt, function (extension) {
2553
+                if (encodedParameters == null) {
2554
+                    encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt);
2555
+                }
2556
+            });
2557
+            if (encodedParameters != null) {
2558
+                return encodedParameters;
2559
+            } else {
2560
+                if (usesFormData(elt)) {
2561
+                    return makeFormData(filteredParameters);
2562
+                } else {
2563
+                    return urlEncode(filteredParameters);
2564
+                }
2565
+            }
2566
+        }
2567
+
2568
+        /**
2569
+         *
2570
+         * @param {Element} target
2571
+         * @returns {import("./htmx").HtmxSettleInfo}
2572
+         */
2573
+        function makeSettleInfo(target) {
2574
+            return {tasks: [], elts: [target]};
2575
+        }
2576
+
2577
+        function updateScrollState(content, swapSpec) {
2578
+            var first = content[0];
2579
+            var last = content[content.length - 1];
2580
+            if (swapSpec.scroll) {
2581
+                var target = null;
2582
+                if (swapSpec.scrollTarget) {
2583
+                    target = querySelectorExt(first, swapSpec.scrollTarget);
2584
+                }
2585
+                if (swapSpec.scroll === "top" && (first || target)) {
2586
+                    target = target || first;
2587
+                    target.scrollTop = 0;
2588
+                }
2589
+                if (swapSpec.scroll === "bottom" && (last || target)) {
2590
+                    target = target || last;
2591
+                    target.scrollTop = target.scrollHeight;
2592
+                }
2593
+            }
2594
+            if (swapSpec.show) {
2595
+                var target = null;
2596
+                if (swapSpec.showTarget) {
2597
+                    var targetStr = swapSpec.showTarget;
2598
+                    if (swapSpec.showTarget === "window") {
2599
+                        targetStr = "body";
2600
+                    }
2601
+                    target = querySelectorExt(first, targetStr);
2602
+                }
2603
+                if (swapSpec.show === "top" && (first || target)) {
2604
+                    target = target || first;
2605
+                    target.scrollIntoView({block:'start', behavior: htmx.config.scrollBehavior});
2606
+                }
2607
+                if (swapSpec.show === "bottom" && (last || target)) {
2608
+                    target = target || last;
2609
+                    target.scrollIntoView({block:'end', behavior: htmx.config.scrollBehavior});
2610
+                }
2611
+            }
2612
+        }
2613
+
2614
+        /**
2615
+         * @param {HTMLElement} elt
2616
+         * @param {string} attr
2617
+         * @param {boolean=} evalAsDefault
2618
+         * @param {Object=} values
2619
+         * @returns {Object}
2620
+         */
2621
+        function getValuesForElement(elt, attr, evalAsDefault, values) {
2622
+            if (values == null) {
2623
+                values = {};
2624
+            }
2625
+            if (elt == null) {
2626
+                return values;
2627
+            }
2628
+            var attributeValue = getAttributeValue(elt, attr);
2629
+            if (attributeValue) {
2630
+                var str = attributeValue.trim();
2631
+                var evaluateValue = evalAsDefault;
2632
+                if (str === "unset") {
2633
+                    return null;
2634
+                }
2635
+                if (str.indexOf("javascript:") === 0) {
2636
+                    str = str.substr(11);
2637
+                    evaluateValue = true;
2638
+                } else if (str.indexOf("js:") === 0) {
2639
+                    str = str.substr(3);
2640
+                    evaluateValue = true;
2641
+                }
2642
+                if (str.indexOf('{') !== 0) {
2643
+                    str = "{" + str + "}";
2644
+                }
2645
+                var varsValues;
2646
+                if (evaluateValue) {
2647
+                    varsValues = maybeEval(elt,function () {return Function("return (" + str + ")")();}, {});
2648
+                } else {
2649
+                    varsValues = parseJSON(str);
2650
+                }
2651
+                for (var key in varsValues) {
2652
+                    if (varsValues.hasOwnProperty(key)) {
2653
+                        if (values[key] == null) {
2654
+                            values[key] = varsValues[key];
2655
+                        }
2656
+                    }
2657
+                }
2658
+            }
2659
+            return getValuesForElement(parentElt(elt), attr, evalAsDefault, values);
2660
+        }
2661
+
2662
+        function maybeEval(elt, toEval, defaultVal) {
2663
+            if (htmx.config.allowEval) {
2664
+                return toEval();
2665
+            } else {
2666
+                triggerErrorEvent(elt, 'htmx:evalDisallowedError');
2667
+                return defaultVal;
2668
+            }
2669
+        }
2670
+
2671
+        /**
2672
+         * @param {HTMLElement} elt
2673
+         * @param {*} expressionVars
2674
+         * @returns
2675
+         */
2676
+        function getHXVarsForElement(elt, expressionVars) {
2677
+            return getValuesForElement(elt, "hx-vars", true, expressionVars);
2678
+        }
2679
+
2680
+        /**
2681
+         * @param {HTMLElement} elt
2682
+         * @param {*} expressionVars
2683
+         * @returns
2684
+         */
2685
+        function getHXValsForElement(elt, expressionVars) {
2686
+            return getValuesForElement(elt, "hx-vals", false, expressionVars);
2687
+        }
2688
+
2689
+        /**
2690
+         * @param {HTMLElement} elt
2691
+         * @returns {Object}
2692
+         */
2693
+        function getExpressionVars(elt) {
2694
+            return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt));
2695
+        }
2696
+
2697
+        function safelySetHeaderValue(xhr, header, headerValue) {
2698
+            if (headerValue !== null) {
2699
+                try {
2700
+                    xhr.setRequestHeader(header, headerValue);
2701
+                } catch (e) {
2702
+                    // On an exception, try to set the header URI encoded instead
2703
+                    xhr.setRequestHeader(header, encodeURIComponent(headerValue));
2704
+                    xhr.setRequestHeader(header + "-URI-AutoEncoded", "true");
2705
+                }
2706
+            }
2707
+        }
2708
+
2709
+        function getPathFromResponse(xhr) {
2710
+            // NB: IE11 does not support this stuff
2711
+            if (xhr.responseURL && typeof(URL) !== "undefined") {
2712
+                try {
2713
+                    var url = new URL(xhr.responseURL);
2714
+                    return url.pathname + url.search;
2715
+                } catch (e) {
2716
+                    triggerErrorEvent(getDocument().body, "htmx:badResponseUrl", {url: xhr.responseURL});
2717
+                }
2718
+            }
2719
+        }
2720
+
2721
+        function hasHeader(xhr, regexp) {
2722
+            return xhr.getAllResponseHeaders().match(regexp);
2723
+        }
2724
+
2725
+        function ajaxHelper(verb, path, context) {
2726
+            verb = verb.toLowerCase();
2727
+            if (context) {
2728
+                if (context instanceof Element || isType(context, 'String')) {
2729
+                    return issueAjaxRequest(verb, path, null, null, {
2730
+                        targetOverride: resolveTarget(context),
2731
+                        returnPromise: true
2732
+                    });
2733
+                } else {
2734
+                    return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event,
2735
+                        {
2736
+                            handler : context.handler,
2737
+                            headers : context.headers,
2738
+                            values : context.values,
2739
+                            targetOverride: resolveTarget(context.target),
2740
+                            swapOverride: context.swap,
2741
+                            returnPromise: true
2742
+                        });
2743
+                }
2744
+            } else {
2745
+                return issueAjaxRequest(verb, path, null, null, {
2746
+                        returnPromise: true
2747
+                });
2748
+            }
2749
+        }
2750
+
2751
+        function hierarchyForElt(elt) {
2752
+            var arr = [];
2753
+            while (elt) {
2754
+                arr.push(elt);
2755
+                elt = elt.parentElement;
2756
+            }
2757
+            return arr;
2758
+        }
2759
+
2760
+        function issueAjaxRequest(verb, path, elt, event, etc, confirmed) {
2761
+            var resolve = null;
2762
+            var reject = null;
2763
+            etc = etc != null ? etc : {};
2764
+            if(etc.returnPromise && typeof Promise !== "undefined"){
2765
+                var promise = new Promise(function (_resolve, _reject) {
2766
+                    resolve = _resolve;
2767
+                    reject = _reject;
2768
+                });
2769
+            }
2770
+            if(elt == null) {
2771
+                elt = getDocument().body;
2772
+            }
2773
+            var responseHandler = etc.handler || handleAjaxResponse;
2774
+
2775
+            if (!bodyContains(elt)) {
2776
+                return; // do not issue requests for elements removed from the DOM
2777
+            }
2778
+            var target = etc.targetOverride || getTarget(elt);
2779
+            if (target == null || target == DUMMY_ELT) {
2780
+                triggerErrorEvent(elt, 'htmx:targetError', {target: getAttributeValue(elt, "hx-target")});
2781
+                return;
2782
+            }
2783
+
2784
+            // allow event-based confirmation w/ a callback
2785
+            if (!confirmed) {
2786
+                var issueRequest = function() {
2787
+                    return issueAjaxRequest(verb, path, elt, event, etc, true);
2788
+                }
2789
+                var confirmDetails = {target: target, elt: elt, path: path, verb: verb, triggeringEvent: event, etc: etc, issueRequest: issueRequest};
2790
+                if (triggerEvent(elt, 'htmx:confirm', confirmDetails) === false) {
2791
+                    return;
2792
+                }
2793
+            }
2794
+
2795
+            var syncElt = elt;
2796
+            var eltData = getInternalData(elt);
2797
+            var syncStrategy = getClosestAttributeValue(elt, "hx-sync");
2798
+            var queueStrategy = null;
2799
+            var abortable = false;
2800
+            if (syncStrategy) {
2801
+                var syncStrings = syncStrategy.split(":");
2802
+                var selector = syncStrings[0].trim();
2803
+                if (selector === "this") {
2804
+                    syncElt = findThisElement(elt, 'hx-sync');
2805
+                } else {
2806
+                    syncElt = querySelectorExt(elt, selector);
2807
+                }
2808
+                // default to the drop strategy
2809
+                syncStrategy = (syncStrings[1] || 'drop').trim();
2810
+                eltData = getInternalData(syncElt);
2811
+                if (syncStrategy === "drop" && eltData.xhr && eltData.abortable !== true) {
2812
+                    return;
2813
+                } else if (syncStrategy === "abort") {
2814
+                    if (eltData.xhr) {
2815
+                        return;
2816
+                    } else {
2817
+                        abortable = true;
2818
+                    }
2819
+                } else if (syncStrategy === "replace") {
2820
+                    triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue
2821
+                } else if (syncStrategy.indexOf("queue") === 0) {
2822
+                    var queueStrArray = syncStrategy.split(" ");
2823
+                    queueStrategy = (queueStrArray[1] || "last").trim();
2824
+                }
2825
+            }
2826
+
2827
+            if (eltData.xhr) {
2828
+                if (eltData.abortable) {
2829
+                    triggerEvent(syncElt, 'htmx:abort'); // abort the current request and continue
2830
+                } else {
2831
+                    if(queueStrategy == null){
2832
+                        if (event) {
2833
+                            var eventData = getInternalData(event);
2834
+                            if (eventData && eventData.triggerSpec && eventData.triggerSpec.queue) {
2835
+                                queueStrategy = eventData.triggerSpec.queue;
2836
+                            }
2837
+                        }
2838
+                        if (queueStrategy == null) {
2839
+                            queueStrategy = "last";
2840
+                        }
2841
+                    }
2842
+                    if (eltData.queuedRequests == null) {
2843
+                        eltData.queuedRequests = [];
2844
+                    }
2845
+                    if (queueStrategy === "first" && eltData.queuedRequests.length === 0) {
2846
+                        eltData.queuedRequests.push(function () {
2847
+                            issueAjaxRequest(verb, path, elt, event, etc)
2848
+                        });
2849
+                    } else if (queueStrategy === "all") {
2850
+                        eltData.queuedRequests.push(function () {
2851
+                            issueAjaxRequest(verb, path, elt, event, etc)
2852
+                        });
2853
+                    } else if (queueStrategy === "last") {
2854
+                        eltData.queuedRequests = []; // dump existing queue
2855
+                        eltData.queuedRequests.push(function () {
2856
+                            issueAjaxRequest(verb, path, elt, event, etc)
2857
+                        });
2858
+                    }
2859
+                    return;
2860
+                }
2861
+            }
2862
+
2863
+            var xhr = new XMLHttpRequest();
2864
+            eltData.xhr = xhr;
2865
+            eltData.abortable = abortable;
2866
+            var endRequestLock = function(){
2867
+                eltData.xhr = null;
2868
+                eltData.abortable = false;
2869
+                if (eltData.queuedRequests != null &&
2870
+                    eltData.queuedRequests.length > 0) {
2871
+                    var queuedRequest = eltData.queuedRequests.shift();
2872
+                    queuedRequest();
2873
+                }
2874
+            }
2875
+            var promptQuestion = getClosestAttributeValue(elt, "hx-prompt");
2876
+            if (promptQuestion) {
2877
+                var promptResponse = prompt(promptQuestion);
2878
+                // prompt returns null if cancelled and empty string if accepted with no entry
2879
+                if (promptResponse === null ||
2880
+                    !triggerEvent(elt, 'htmx:prompt', {prompt: promptResponse, target:target})) {
2881
+                    maybeCall(resolve);
2882
+                    endRequestLock();
2883
+                    return promise;
2884
+                }
2885
+            }
2886
+
2887
+            var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm");
2888
+            if (confirmQuestion) {
2889
+                if(!confirm(confirmQuestion)) {
2890
+                    maybeCall(resolve);
2891
+                    endRequestLock()
2892
+                    return promise;
2893
+                }
2894
+            }
2895
+
2896
+
2897
+            var headers = getHeaders(elt, target, promptResponse);
2898
+            if (etc.headers) {
2899
+                headers = mergeObjects(headers, etc.headers);
2900
+            }
2901
+            var results = getInputValues(elt, verb);
2902
+            var errors = results.errors;
2903
+            var rawParameters = results.values;
2904
+            if (etc.values) {
2905
+                rawParameters = mergeObjects(rawParameters, etc.values);
2906
+            }
2907
+            var expressionVars = getExpressionVars(elt);
2908
+            var allParameters = mergeObjects(rawParameters, expressionVars);
2909
+            var filteredParameters = filterValues(allParameters, elt);
2910
+
2911
+            if (verb !== 'get' && !usesFormData(elt)) {
2912
+                headers['Content-Type'] = 'application/x-www-form-urlencoded';
2913
+            }
2914
+
2915
+            if (htmx.config.getCacheBusterParam && verb === 'get') {
2916
+                filteredParameters['org.htmx.cache-buster'] = getRawAttribute(target, "id") || "true";
2917
+            }
2918
+
2919
+            // behavior of anchors w/ empty href is to use the current URL
2920
+            if (path == null || path === "") {
2921
+                path = getDocument().location.href;
2922
+            }
2923
+
2924
+
2925
+            var requestAttrValues = getValuesForElement(elt, 'hx-request');
2926
+
2927
+            var eltIsBoosted = getInternalData(elt).boosted;
2928
+            var requestConfig = {
2929
+                boosted: eltIsBoosted,
2930
+                parameters: filteredParameters,
2931
+                unfilteredParameters: allParameters,
2932
+                headers:headers,
2933
+                target:target,
2934
+                verb:verb,
2935
+                errors:errors,
2936
+                withCredentials: etc.credentials || requestAttrValues.credentials || htmx.config.withCredentials,
2937
+                timeout:  etc.timeout || requestAttrValues.timeout || htmx.config.timeout,
2938
+                path:path,
2939
+                triggeringEvent:event
2940
+            };
2941
+
2942
+            if(!triggerEvent(elt, 'htmx:configRequest', requestConfig)){
2943
+                maybeCall(resolve);
2944
+                endRequestLock();
2945
+                return promise;
2946
+            }
2947
+
2948
+            // copy out in case the object was overwritten
2949
+            path = requestConfig.path;
2950
+            verb = requestConfig.verb;
2951
+            headers = requestConfig.headers;
2952
+            filteredParameters = requestConfig.parameters;
2953
+            errors = requestConfig.errors;
2954
+
2955
+            if(errors && errors.length > 0){
2956
+                triggerEvent(elt, 'htmx:validation:halted', requestConfig)
2957
+                maybeCall(resolve);
2958
+                endRequestLock();
2959
+                return promise;
2960
+            }
2961
+
2962
+            var splitPath = path.split("#");
2963
+            var pathNoAnchor = splitPath[0];
2964
+            var anchor = splitPath[1];
2965
+            var finalPathForGet = null;
2966
+            if (verb === 'get') {
2967
+                finalPathForGet = pathNoAnchor;
2968
+                var values = Object.keys(filteredParameters).length !== 0;
2969
+                if (values) {
2970
+                    if (finalPathForGet.indexOf("?") < 0) {
2971
+                        finalPathForGet += "?";
2972
+                    } else {
2973
+                        finalPathForGet += "&";
2974
+                    }
2975
+                    finalPathForGet += urlEncode(filteredParameters);
2976
+                    if (anchor) {
2977
+                        finalPathForGet += "#" + anchor;
2978
+                    }
2979
+                }
2980
+                xhr.open('GET', finalPathForGet, true);
2981
+            } else {
2982
+                xhr.open(verb.toUpperCase(), path, true);
2983
+            }
2984
+
2985
+            xhr.overrideMimeType("text/html");
2986
+            xhr.withCredentials = requestConfig.withCredentials;
2987
+            xhr.timeout = requestConfig.timeout;
2988
+
2989
+            // request headers
2990
+            if (requestAttrValues.noHeaders) {
2991
+                // ignore all headers
2992
+            } else {
2993
+                for (var header in headers) {
2994
+                    if (headers.hasOwnProperty(header)) {
2995
+                        var headerValue = headers[header];
2996
+                        safelySetHeaderValue(xhr, header, headerValue);
2997
+                    }
2998
+                }
2999
+            }
3000
+
3001
+            var responseInfo = {
3002
+                xhr: xhr, target: target, requestConfig: requestConfig, etc: etc, boosted: eltIsBoosted,
3003
+                pathInfo: {
3004
+                    requestPath: path,
3005
+                    finalRequestPath: finalPathForGet || path,
3006
+                    anchor: anchor
3007
+                }
3008
+            };
3009
+
3010
+            xhr.onload = function () {
3011
+                try {
3012
+                    var hierarchy = hierarchyForElt(elt);
3013
+                    responseInfo.pathInfo.responsePath = getPathFromResponse(xhr);
3014
+                    responseHandler(elt, responseInfo);
3015
+                    removeRequestIndicatorClasses(indicators);
3016
+                    triggerEvent(elt, 'htmx:afterRequest', responseInfo);
3017
+                    triggerEvent(elt, 'htmx:afterOnLoad', responseInfo);
3018
+                    // if the body no longer contains the element, trigger the event on the closest parent
3019
+                    // remaining in the DOM
3020
+                    if (!bodyContains(elt)) {
3021
+                        var secondaryTriggerElt = null;
3022
+                        while (hierarchy.length > 0 && secondaryTriggerElt == null) {
3023
+                            var parentEltInHierarchy = hierarchy.shift();
3024
+                            if (bodyContains(parentEltInHierarchy)) {
3025
+                                secondaryTriggerElt = parentEltInHierarchy;
3026
+                            }
3027
+                        }
3028
+                        if (secondaryTriggerElt) {
3029
+                            triggerEvent(secondaryTriggerElt, 'htmx:afterRequest', responseInfo);
3030
+                            triggerEvent(secondaryTriggerElt, 'htmx:afterOnLoad', responseInfo);
3031
+                        }
3032
+                    }
3033
+                    maybeCall(resolve);
3034
+                    endRequestLock();
3035
+                } catch (e) {
3036
+                    triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({error:e}, responseInfo));
3037
+                    throw e;
3038
+                }
3039
+            }
3040
+            xhr.onerror = function () {
3041
+                removeRequestIndicatorClasses(indicators);
3042
+                triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo);
3043
+                triggerErrorEvent(elt, 'htmx:sendError', responseInfo);
3044
+                maybeCall(reject);
3045
+                endRequestLock();
3046
+            }
3047
+            xhr.onabort = function() {
3048
+                removeRequestIndicatorClasses(indicators);
3049
+                triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo);
3050
+                triggerErrorEvent(elt, 'htmx:sendAbort', responseInfo);
3051
+                maybeCall(reject);
3052
+                endRequestLock();
3053
+            }
3054
+            xhr.ontimeout = function() {
3055
+                removeRequestIndicatorClasses(indicators);
3056
+                triggerErrorEvent(elt, 'htmx:afterRequest', responseInfo);
3057
+                triggerErrorEvent(elt, 'htmx:timeout', responseInfo);
3058
+                maybeCall(reject);
3059
+                endRequestLock();
3060
+            }
3061
+            if(!triggerEvent(elt, 'htmx:beforeRequest', responseInfo)){
3062
+                maybeCall(resolve);
3063
+                endRequestLock()
3064
+                return promise
3065
+            }
3066
+            var indicators = addRequestIndicatorClasses(elt);
3067
+
3068
+            forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) {
3069
+                forEach([xhr, xhr.upload], function (target) {
3070
+                    target.addEventListener(eventName, function(event){
3071
+                        triggerEvent(elt, "htmx:xhr:" + eventName, {
3072
+                            lengthComputable:event.lengthComputable,
3073
+                            loaded:event.loaded,
3074
+                            total:event.total
3075
+                        });
3076
+                    })
3077
+                });
3078
+            });
3079
+            triggerEvent(elt, 'htmx:beforeSend', responseInfo);
3080
+            xhr.send(verb === 'get' ? null : encodeParamsForBody(xhr, elt, filteredParameters));
3081
+            return promise;
3082
+        }
3083
+
3084
+        function determineHistoryUpdates(elt, responseInfo) {
3085
+
3086
+            var xhr = responseInfo.xhr;
3087
+
3088
+            //===========================================
3089
+            // First consult response headers
3090
+            //===========================================
3091
+            var pathFromHeaders = null;
3092
+            var typeFromHeaders = null;
3093
+            if (hasHeader(xhr,/HX-Push:/i)) {
3094
+                pathFromHeaders = xhr.getResponseHeader("HX-Push");
3095
+                typeFromHeaders = "push";
3096
+            } else if (hasHeader(xhr,/HX-Push-Url:/i)) {
3097
+                pathFromHeaders = xhr.getResponseHeader("HX-Push-Url");
3098
+                typeFromHeaders = "push";
3099
+            } else if (hasHeader(xhr,/HX-Replace-Url:/i)) {
3100
+                pathFromHeaders = xhr.getResponseHeader("HX-Replace-Url");
3101
+                typeFromHeaders = "replace";
3102
+            }
3103
+
3104
+            // if there was a response header, that has priority
3105
+            if (pathFromHeaders) {
3106
+                if (pathFromHeaders === "false") {
3107
+                    return {}
3108
+                } else {
3109
+                    return {
3110
+                        type: typeFromHeaders,
3111
+                        path : pathFromHeaders
3112
+                    }
3113
+                }
3114
+            }
3115
+
3116
+            //===========================================
3117
+            // Next resolve via DOM values
3118
+            //===========================================
3119
+            var requestPath =  responseInfo.pathInfo.finalRequestPath;
3120
+            var responsePath =  responseInfo.pathInfo.responsePath;
3121
+
3122
+            var pushUrl = getClosestAttributeValue(elt, "hx-push-url");
3123
+            var replaceUrl = getClosestAttributeValue(elt, "hx-replace-url");
3124
+            var elementIsBoosted = getInternalData(elt).boosted;
3125
+
3126
+            var saveType = null;
3127
+            var path = null;
3128
+
3129
+            if (pushUrl) {
3130
+                saveType = "push";
3131
+                path = pushUrl;
3132
+            } else if (replaceUrl) {
3133
+                saveType = "replace";
3134
+                path = replaceUrl;
3135
+            } else if (elementIsBoosted) {
3136
+                saveType = "push";
3137
+                path = responsePath || requestPath; // if there is no response path, go with the original request path
3138
+            }
3139
+
3140
+            if (path) {
3141
+                // false indicates no push, return empty object
3142
+                if (path === "false") {
3143
+                    return {};
3144
+                }
3145
+
3146
+                // true indicates we want to follow wherever the server ended up sending us
3147
+                if (path === "true") {
3148
+                    path = responsePath || requestPath; // if there is no response path, go with the original request path
3149
+                }
3150
+
3151
+                // restore any anchor associated with the request
3152
+                if (responseInfo.pathInfo.anchor &&
3153
+                    path.indexOf("#") === -1) {
3154
+                    path = path + "#" + responseInfo.pathInfo.anchor;
3155
+                }
3156
+
3157
+                return {
3158
+                    type:saveType,
3159
+                    path: path
3160
+                }
3161
+            } else {
3162
+                return {};
3163
+            }
3164
+        }
3165
+
3166
+        function handleAjaxResponse(elt, responseInfo) {
3167
+            var xhr = responseInfo.xhr;
3168
+            var target = responseInfo.target;
3169
+            var etc = responseInfo.etc;
3170
+
3171
+            if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return;
3172
+
3173
+            if (hasHeader(xhr, /HX-Trigger:/i)) {
3174
+                handleTrigger(xhr, "HX-Trigger", elt);
3175
+            }
3176
+
3177
+            if (hasHeader(xhr, /HX-Location:/i)) {
3178
+                saveCurrentPageToHistory();
3179
+                var redirectPath = xhr.getResponseHeader("HX-Location");
3180
+                var swapSpec;
3181
+                if (redirectPath.indexOf("{") === 0) {
3182
+                    swapSpec = parseJSON(redirectPath);
3183
+                    // what's the best way to throw an error if the user didn't include this
3184
+                    redirectPath = swapSpec['path'];
3185
+                    delete swapSpec['path'];
3186
+                }
3187
+                ajaxHelper('GET', redirectPath, swapSpec).then(function(){
3188
+                    pushUrlIntoHistory(redirectPath);
3189
+                });
3190
+                return;
3191
+            }
3192
+
3193
+            if (hasHeader(xhr, /HX-Redirect:/i)) {
3194
+                location.href = xhr.getResponseHeader("HX-Redirect");
3195
+                return;
3196
+            }
3197
+
3198
+            if (hasHeader(xhr,/HX-Refresh:/i)) {
3199
+                if ("true" === xhr.getResponseHeader("HX-Refresh")) {
3200
+                    location.reload();
3201
+                    return;
3202
+                }
3203
+            }
3204
+
3205
+            if (hasHeader(xhr,/HX-Retarget:/i)) {
3206
+                responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget"));
3207
+            }
3208
+
3209
+            var historyUpdate = determineHistoryUpdates(elt, responseInfo);
3210
+
3211
+            // by default htmx only swaps on 200 return codes and does not swap
3212
+            // on 204 'No Content'
3213
+            // this can be ovverriden by responding to the htmx:beforeSwap event and
3214
+            // overriding the detail.shouldSwap property
3215
+            var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204;
3216
+            var serverResponse = xhr.response;
3217
+            var isError = xhr.status >= 400;
3218
+            var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError}, responseInfo);
3219
+            if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return;
3220
+
3221
+            target = beforeSwapDetails.target; // allow re-targeting
3222
+            serverResponse = beforeSwapDetails.serverResponse; // allow updating content
3223
+            isError = beforeSwapDetails.isError; // allow updating error
3224
+
3225
+            responseInfo.target = target; // Make updated target available to response events
3226
+            responseInfo.failed = isError; // Make failed property available to response events
3227
+            responseInfo.successful = !isError; // Make successful property available to response events
3228
+
3229
+            if (beforeSwapDetails.shouldSwap) {
3230
+                if (xhr.status === 286) {
3231
+                    cancelPolling(elt);
3232
+                }
3233
+
3234
+                withExtensions(elt, function (extension) {
3235
+                    serverResponse = extension.transformResponse(serverResponse, xhr, elt);
3236
+                });
3237
+
3238
+                // Save current page if there will be a history update
3239
+                if (historyUpdate.type) {
3240
+                    saveCurrentPageToHistory();
3241
+                }
3242
+
3243
+                var swapOverride = etc.swapOverride;
3244
+                if (hasHeader(xhr,/HX-Reswap:/i)) {
3245
+                    swapOverride = xhr.getResponseHeader("HX-Reswap");
3246
+                }
3247
+                var swapSpec = getSwapSpecification(elt, swapOverride);
3248
+
3249
+                target.classList.add(htmx.config.swappingClass);
3250
+
3251
+                // optional transition API promise callbacks
3252
+                var settleResolve = null;
3253
+                var settleReject = null;
3254
+
3255
+                var doSwap = function () {
3256
+                    try {
3257
+                        var activeElt = document.activeElement;
3258
+                        var selectionInfo = {};
3259
+                        try {
3260
+                            selectionInfo = {
3261
+                                elt: activeElt,
3262
+                                // @ts-ignore
3263
+                                start: activeElt ? activeElt.selectionStart : null,
3264
+                                // @ts-ignore
3265
+                                end: activeElt ? activeElt.selectionEnd : null
3266
+                            };
3267
+                        } catch (e) {
3268
+                            // safari issue - see https://github.com/microsoft/playwright/issues/5894
3269
+                        }
3270
+
3271
+                        var settleInfo = makeSettleInfo(target);
3272
+                        selectAndSwap(swapSpec.swapStyle, target, elt, serverResponse, settleInfo);
3273
+
3274
+                        if (selectionInfo.elt &&
3275
+                            !bodyContains(selectionInfo.elt) &&
3276
+                            selectionInfo.elt.id) {
3277
+                            var newActiveElt = document.getElementById(selectionInfo.elt.id);
3278
+                            var focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll };
3279
+                            if (newActiveElt) {
3280
+                                // @ts-ignore
3281
+                                if (selectionInfo.start && newActiveElt.setSelectionRange) {
3282
+                                    // @ts-ignore
3283
+                                    try {
3284
+                                        newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end);
3285
+                                    } catch (e) {
3286
+                                        // the setSelectionRange method is present on fields that don't support it, so just let this fail
3287
+                                    }
3288
+                                }
3289
+                                newActiveElt.focus(focusOptions);
3290
+                            }
3291
+                        }
3292
+
3293
+                        target.classList.remove(htmx.config.swappingClass);
3294
+                        forEach(settleInfo.elts, function (elt) {
3295
+                            if (elt.classList) {
3296
+                                elt.classList.add(htmx.config.settlingClass);
3297
+                            }
3298
+                            triggerEvent(elt, 'htmx:afterSwap', responseInfo);
3299
+                        });
3300
+
3301
+                        if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) {
3302
+                            var finalElt = elt;
3303
+                            if (!bodyContains(elt)) {
3304
+                                finalElt = getDocument().body;
3305
+                            }
3306
+                            handleTrigger(xhr, "HX-Trigger-After-Swap", finalElt);
3307
+                        }
3308
+
3309
+                        var doSettle = function () {
3310
+                            forEach(settleInfo.tasks, function (task) {
3311
+                                task.call();
3312
+                            });
3313
+                            forEach(settleInfo.elts, function (elt) {
3314
+                                if (elt.classList) {
3315
+                                    elt.classList.remove(htmx.config.settlingClass);
3316
+                                }
3317
+                                triggerEvent(elt, 'htmx:afterSettle', responseInfo);
3318
+                            });
3319
+
3320
+                            // if we need to save history, do so
3321
+                            if (historyUpdate.type) {
3322
+                                if (historyUpdate.type === "push") {
3323
+                                    pushUrlIntoHistory(historyUpdate.path);
3324
+                                    triggerEvent(getDocument().body, 'htmx:pushedIntoHistory', {path: historyUpdate.path});
3325
+                                } else {
3326
+                                    replaceUrlInHistory(historyUpdate.path);
3327
+                                    triggerEvent(getDocument().body, 'htmx:replacedInHistory', {path: historyUpdate.path});
3328
+                                }
3329
+                            }
3330
+                            if (responseInfo.pathInfo.anchor) {
3331
+                                var anchorTarget = find("#" + responseInfo.pathInfo.anchor);
3332
+                                if(anchorTarget) {
3333
+                                    anchorTarget.scrollIntoView({block:'start', behavior: "auto"});
3334
+                                }
3335
+                            }
3336
+
3337
+                            if(settleInfo.title) {
3338
+                                var titleElt = find("title");
3339
+                                if(titleElt) {
3340
+                                    titleElt.innerHTML = settleInfo.title;
3341
+                                } else {
3342
+                                    window.document.title = settleInfo.title;
3343
+                                }
3344
+                            }
3345
+
3346
+                            updateScrollState(settleInfo.elts, swapSpec);
3347
+
3348
+                            if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) {
3349
+                                var finalElt = elt;
3350
+                                if (!bodyContains(elt)) {
3351
+                                    finalElt = getDocument().body;
3352
+                                }
3353
+                                handleTrigger(xhr, "HX-Trigger-After-Settle", finalElt);
3354
+                            }
3355
+                            maybeCall(settleResolve);
3356
+                        }
3357
+
3358
+                        if (swapSpec.settleDelay > 0) {
3359
+                            setTimeout(doSettle, swapSpec.settleDelay)
3360
+                        } else {
3361
+                            doSettle();
3362
+                        }
3363
+                    } catch (e) {
3364
+                        triggerErrorEvent(elt, 'htmx:swapError', responseInfo);
3365
+                        maybeCall(settleReject);
3366
+                        throw e;
3367
+                    }
3368
+                };
3369
+
3370
+                var shouldTransition = htmx.config.globalViewTransitions
3371
+                if(swapSpec.hasOwnProperty('transition')){
3372
+                    shouldTransition = swapSpec.transition;
3373
+                }
3374
+
3375
+                if(shouldTransition &&
3376
+                    triggerEvent(elt, 'htmx:beforeTransition', responseInfo) &&
3377
+                    typeof Promise !== "undefined" && document.startViewTransition){
3378
+                    var settlePromise = new Promise(function (_resolve, _reject) {
3379
+                        settleResolve = _resolve;
3380
+                        settleReject = _reject;
3381
+                    });
3382
+                    // wrap the original doSwap() in a call to startViewTransition()
3383
+                    var innerDoSwap = doSwap;
3384
+                    doSwap = function() {
3385
+                        document.startViewTransition(function () {
3386
+                            innerDoSwap();
3387
+                            return settlePromise;
3388
+                        });
3389
+                    }
3390
+                }
3391
+
3392
+
3393
+                if (swapSpec.swapDelay > 0) {
3394
+                    setTimeout(doSwap, swapSpec.swapDelay)
3395
+                } else {
3396
+                    doSwap();
3397
+                }
3398
+            }
3399
+            if (isError) {
3400
+                triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({error: "Response Status Error Code " + xhr.status + " from " + responseInfo.pathInfo.requestPath}, responseInfo));
3401
+            }
3402
+        }
3403
+
3404
+        //====================================================================
3405
+        // Extensions API
3406
+        //====================================================================
3407
+
3408
+        /** @type {Object<string, import("./htmx").HtmxExtension>} */
3409
+        var extensions = {};
3410
+
3411
+        /**
3412
+         * extensionBase defines the default functions for all extensions.
3413
+         * @returns {import("./htmx").HtmxExtension}
3414
+         */
3415
+        function extensionBase() {
3416
+            return {
3417
+                init: function(api) {return null;},
3418
+                onEvent : function(name, evt) {return true;},
3419
+                transformResponse : function(text, xhr, elt) {return text;},
3420
+                isInlineSwap : function(swapStyle) {return false;},
3421
+                handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;},
3422
+                encodeParameters : function(xhr, parameters, elt) {return null;}
3423
+            }
3424
+        }
3425
+
3426
+        /**
3427
+         * defineExtension initializes the extension and adds it to the htmx registry
3428
+         *
3429
+         * @param {string} name
3430
+         * @param {import("./htmx").HtmxExtension} extension
3431
+         */
3432
+        function defineExtension(name, extension) {
3433
+            if(extension.init) {
3434
+                extension.init(internalAPI)
3435
+            }
3436
+            extensions[name] = mergeObjects(extensionBase(), extension);
3437
+        }
3438
+
3439
+        /**
3440
+         * removeExtension removes an extension from the htmx registry
3441
+         *
3442
+         * @param {string} name
3443
+         */
3444
+        function removeExtension(name) {
3445
+            delete extensions[name];
3446
+        }
3447
+
3448
+        /**
3449
+         * getExtensions searches up the DOM tree to return all extensions that can be applied to a given element
3450
+         *
3451
+         * @param {HTMLElement} elt
3452
+         * @param {import("./htmx").HtmxExtension[]=} extensionsToReturn
3453
+         * @param {import("./htmx").HtmxExtension[]=} extensionsToIgnore
3454
+         */
3455
+         function getExtensions(elt, extensionsToReturn, extensionsToIgnore) {
3456
+
3457
+            if (elt == undefined) {
3458
+                return extensionsToReturn;
3459
+            }
3460
+            if (extensionsToReturn == undefined) {
3461
+                extensionsToReturn = [];
3462
+            }
3463
+            if (extensionsToIgnore == undefined) {
3464
+                extensionsToIgnore = [];
3465
+            }
3466
+            var extensionsForElement = getAttributeValue(elt, "hx-ext");
3467
+            if (extensionsForElement) {
3468
+                forEach(extensionsForElement.split(","), function(extensionName){
3469
+                    extensionName = extensionName.replace(/ /g, '');
3470
+                    if (extensionName.slice(0, 7) == "ignore:") {
3471
+                        extensionsToIgnore.push(extensionName.slice(7));
3472
+                        return;
3473
+                    }
3474
+                    if (extensionsToIgnore.indexOf(extensionName) < 0) {
3475
+                        var extension = extensions[extensionName];
3476
+                        if (extension && extensionsToReturn.indexOf(extension) < 0) {
3477
+                            extensionsToReturn.push(extension);
3478
+                        }
3479
+                    }
3480
+                });
3481
+            }
3482
+            return getExtensions(parentElt(elt), extensionsToReturn, extensionsToIgnore);
3483
+        }
3484
+
3485
+        //====================================================================
3486
+        // Initialization
3487
+        //====================================================================
3488
+
3489
+        function ready(fn) {
3490
+            if (getDocument().readyState !== 'loading') {
3491
+                fn();
3492
+            } else {
3493
+                getDocument().addEventListener('DOMContentLoaded', fn);
3494
+            }
3495
+        }
3496
+
3497
+        function insertIndicatorStyles() {
3498
+            if (htmx.config.includeIndicatorStyles !== false) {
3499
+                getDocument().head.insertAdjacentHTML("beforeend",
3500
+                    "<style>\
3501
+                      ." + htmx.config.indicatorClass + "{opacity:0;transition: opacity 200ms ease-in;}\
3502
+                      ." + htmx.config.requestClass + " ." + htmx.config.indicatorClass + "{opacity:1}\
3503
+                      ." + htmx.config.requestClass + "." + htmx.config.indicatorClass + "{opacity:1}\
3504
+                    </style>");
3505
+            }
3506
+        }
3507
+
3508
+        function getMetaConfig() {
3509
+            var element = getDocument().querySelector('meta[name="htmx-config"]');
3510
+            if (element) {
3511
+                // @ts-ignore
3512
+                return parseJSON(element.content);
3513
+            } else {
3514
+                return null;
3515
+            }
3516
+        }
3517
+
3518
+        function mergeMetaConfig() {
3519
+            var metaConfig = getMetaConfig();
3520
+            if (metaConfig) {
3521
+                htmx.config = mergeObjects(htmx.config , metaConfig)
3522
+            }
3523
+        }
3524
+
3525
+        // initialize the document
3526
+        ready(function () {
3527
+            mergeMetaConfig();
3528
+            insertIndicatorStyles();
3529
+            var body = getDocument().body;
3530
+            processNode(body);
3531
+            var restoredElts = getDocument().querySelectorAll(
3532
+                "[hx-trigger='restored'],[data-hx-trigger='restored']"
3533
+            );
3534
+            body.addEventListener("htmx:abort", function (evt) {
3535
+                var target = evt.target;
3536
+                var internalData = getInternalData(target);
3537
+                if (internalData && internalData.xhr) {
3538
+                    internalData.xhr.abort();
3539
+                }
3540
+            });
3541
+            var originalPopstate = window.onpopstate;
3542
+            window.onpopstate = function (event) {
3543
+                if (event.state && event.state.htmx) {
3544
+                    restoreHistory();
3545
+                    forEach(restoredElts, function(elt){
3546
+                        triggerEvent(elt, 'htmx:restored', {
3547
+                            'document': getDocument(),
3548
+                            'triggerEvent': triggerEvent
3549
+                        });
3550
+                    });
3551
+                } else {
3552
+                    if (originalPopstate) {
3553
+                        originalPopstate(event);
3554
+                    }
3555
+                }
3556
+            };
3557
+            setTimeout(function () {
3558
+                triggerEvent(body, 'htmx:load', {}); // give ready handlers a chance to load up before firing this event
3559
+                body = null; // kill reference for gc
3560
+            }, 0);
3561
+        })
3562
+
3563
+        return htmx;
3564
+    }
3565
+)()
3566
+}));