htmx.org 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -5
- package/dist/ext/response-targets.js +1 -1
- package/dist/htmx.amd.js +585 -480
- package/dist/htmx.cjs.js +585 -480
- package/dist/htmx.esm.d.ts +9 -3
- package/dist/htmx.esm.js +585 -480
- package/dist/htmx.js +585 -480
- package/dist/htmx.min.js +1 -1
- package/dist/htmx.min.js.gz +0 -0
- package/editors/jetbrains/htmx.web-types.json +398 -85
- package/package.json +32 -15
package/dist/htmx.cjs.js
CHANGED
|
@@ -82,7 +82,7 @@ var htmx = (function() {
|
|
|
82
82
|
*/
|
|
83
83
|
historyEnabled: true,
|
|
84
84
|
/**
|
|
85
|
-
* The number of pages to keep in **
|
|
85
|
+
* The number of pages to keep in **sessionStorage** for history support.
|
|
86
86
|
* @type number
|
|
87
87
|
* @default 10
|
|
88
88
|
*/
|
|
@@ -271,13 +271,25 @@ var htmx = (function() {
|
|
|
271
271
|
* @type boolean
|
|
272
272
|
* @default true
|
|
273
273
|
*/
|
|
274
|
-
allowNestedOobSwaps: true
|
|
274
|
+
allowNestedOobSwaps: true,
|
|
275
|
+
/**
|
|
276
|
+
* Whether to treat history cache miss full page reload requests as a "HX-Request" by returning this response header
|
|
277
|
+
* This should always be disabled when using HX-Request header to optionally return partial responses
|
|
278
|
+
* @type boolean
|
|
279
|
+
* @default true
|
|
280
|
+
*/
|
|
281
|
+
historyRestoreAsHxRequest: true
|
|
275
282
|
},
|
|
276
283
|
/** @type {typeof parseInterval} */
|
|
277
284
|
parseInterval: null,
|
|
285
|
+
/**
|
|
286
|
+
* proxy of window.location used for page reload functions
|
|
287
|
+
* @type location
|
|
288
|
+
*/
|
|
289
|
+
location,
|
|
278
290
|
/** @type {typeof internalEval} */
|
|
279
291
|
_: null,
|
|
280
|
-
version: '2.0.
|
|
292
|
+
version: '2.0.5'
|
|
281
293
|
}
|
|
282
294
|
// Tsc madness part 2
|
|
283
295
|
htmx.onLoad = onLoadHelper
|
|
@@ -484,10 +496,7 @@ var htmx = (function() {
|
|
|
484
496
|
* @returns {boolean}
|
|
485
497
|
*/
|
|
486
498
|
function matches(elt, selector) {
|
|
487
|
-
|
|
488
|
-
// noinspection JSUnresolvedVariable
|
|
489
|
-
const matchesFunction = elt instanceof Element && (elt.matches || elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector || elt.webkitMatchesSelector || elt.oMatchesSelector)
|
|
490
|
-
return !!matchesFunction && matchesFunction.call(elt, selector)
|
|
499
|
+
return elt instanceof Element && elt.matches(selector)
|
|
491
500
|
}
|
|
492
501
|
|
|
493
502
|
/**
|
|
@@ -693,6 +702,7 @@ var htmx = (function() {
|
|
|
693
702
|
* @property {XMLHttpRequest} [xhr]
|
|
694
703
|
* @property {(() => void)[]} [queuedRequests]
|
|
695
704
|
* @property {boolean} [abortable]
|
|
705
|
+
* @property {boolean} [firstInitCompleted]
|
|
696
706
|
*
|
|
697
707
|
* Event data
|
|
698
708
|
* @property {HtmxTriggerSpecification} [triggerSpec]
|
|
@@ -754,17 +764,14 @@ var htmx = (function() {
|
|
|
754
764
|
}
|
|
755
765
|
|
|
756
766
|
/**
|
|
767
|
+
* Checks whether the element is in the document (includes shadow roots).
|
|
768
|
+
* This function this is a slight misnomer; it will return true even for elements in the head.
|
|
769
|
+
*
|
|
757
770
|
* @param {Node} elt
|
|
758
771
|
* @returns {boolean}
|
|
759
772
|
*/
|
|
760
773
|
function bodyContains(elt) {
|
|
761
|
-
|
|
762
|
-
const rootNode = elt.getRootNode && elt.getRootNode()
|
|
763
|
-
if (rootNode && rootNode instanceof window.ShadowRoot) {
|
|
764
|
-
return getDocument().body.contains(rootNode.host)
|
|
765
|
-
} else {
|
|
766
|
-
return getDocument().body.contains(elt)
|
|
767
|
-
}
|
|
774
|
+
return elt.getRootNode({ composed: true }) === document
|
|
768
775
|
}
|
|
769
776
|
|
|
770
777
|
/**
|
|
@@ -812,10 +819,10 @@ var htmx = (function() {
|
|
|
812
819
|
* @returns {boolean}
|
|
813
820
|
*/
|
|
814
821
|
function canAccessLocalStorage() {
|
|
815
|
-
const test = 'htmx:
|
|
822
|
+
const test = 'htmx:sessionStorageTest'
|
|
816
823
|
try {
|
|
817
|
-
|
|
818
|
-
|
|
824
|
+
sessionStorage.setItem(test, test)
|
|
825
|
+
sessionStorage.removeItem(test)
|
|
819
826
|
return true
|
|
820
827
|
} catch (e) {
|
|
821
828
|
return false
|
|
@@ -827,20 +834,16 @@ var htmx = (function() {
|
|
|
827
834
|
* @returns {string}
|
|
828
835
|
*/
|
|
829
836
|
function normalizePath(path) {
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
}
|
|
839
|
-
return path
|
|
840
|
-
} catch (e) {
|
|
841
|
-
// be kind to IE11, which doesn't support URL()
|
|
842
|
-
return path
|
|
837
|
+
// use dummy base URL to allow normalize on path only
|
|
838
|
+
const url = new URL(path, 'http://x')
|
|
839
|
+
if (url) {
|
|
840
|
+
path = url.pathname + url.search
|
|
841
|
+
}
|
|
842
|
+
// remove trailing slash, unless index page
|
|
843
|
+
if (path != '/') {
|
|
844
|
+
path = path.replace(/\/+$/, '')
|
|
843
845
|
}
|
|
846
|
+
return path
|
|
844
847
|
}
|
|
845
848
|
|
|
846
849
|
//= =========================================================================================
|
|
@@ -1076,18 +1079,10 @@ var htmx = (function() {
|
|
|
1076
1079
|
*/
|
|
1077
1080
|
function closest(elt, selector) {
|
|
1078
1081
|
elt = asElement(resolveTarget(elt))
|
|
1079
|
-
if (elt
|
|
1082
|
+
if (elt) {
|
|
1080
1083
|
return elt.closest(selector)
|
|
1081
|
-
} else {
|
|
1082
|
-
// TODO remove when IE goes away
|
|
1083
|
-
do {
|
|
1084
|
-
if (elt == null || matches(elt, selector)) {
|
|
1085
|
-
return elt
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
while (elt = elt && asElement(parentElt(elt)))
|
|
1089
|
-
return null
|
|
1090
1084
|
}
|
|
1085
|
+
return null
|
|
1091
1086
|
}
|
|
1092
1087
|
|
|
1093
1088
|
/**
|
|
@@ -1128,34 +1123,77 @@ var htmx = (function() {
|
|
|
1128
1123
|
* @returns {(Node|Window)[]}
|
|
1129
1124
|
*/
|
|
1130
1125
|
function querySelectorAllExt(elt, selector, global) {
|
|
1131
|
-
|
|
1132
|
-
if (selector.indexOf('closest ') === 0) {
|
|
1133
|
-
return [closest(asElement(elt), normalizeSelector(selector.substr(8)))]
|
|
1134
|
-
} else if (selector.indexOf('find ') === 0) {
|
|
1135
|
-
return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))]
|
|
1136
|
-
} else if (selector === 'next') {
|
|
1137
|
-
return [asElement(elt).nextElementSibling]
|
|
1138
|
-
} else if (selector.indexOf('next ') === 0) {
|
|
1139
|
-
return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)]
|
|
1140
|
-
} else if (selector === 'previous') {
|
|
1141
|
-
return [asElement(elt).previousElementSibling]
|
|
1142
|
-
} else if (selector.indexOf('previous ') === 0) {
|
|
1143
|
-
return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)]
|
|
1144
|
-
} else if (selector === 'document') {
|
|
1145
|
-
return [document]
|
|
1146
|
-
} else if (selector === 'window') {
|
|
1147
|
-
return [window]
|
|
1148
|
-
} else if (selector === 'body') {
|
|
1149
|
-
return [document.body]
|
|
1150
|
-
} else if (selector === 'root') {
|
|
1151
|
-
return [getRootNode(elt, !!global)]
|
|
1152
|
-
} else if (selector === 'host') {
|
|
1153
|
-
return [(/** @type ShadowRoot */(elt.getRootNode())).host]
|
|
1154
|
-
} else if (selector.indexOf('global ') === 0) {
|
|
1126
|
+
if (selector.indexOf('global ') === 0) {
|
|
1155
1127
|
return querySelectorAllExt(elt, selector.slice(7), true)
|
|
1156
|
-
} else {
|
|
1157
|
-
return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector)))
|
|
1158
1128
|
}
|
|
1129
|
+
|
|
1130
|
+
elt = resolveTarget(elt)
|
|
1131
|
+
|
|
1132
|
+
const parts = []
|
|
1133
|
+
{
|
|
1134
|
+
let chevronsCount = 0
|
|
1135
|
+
let offset = 0
|
|
1136
|
+
for (let i = 0; i < selector.length; i++) {
|
|
1137
|
+
const char = selector[i]
|
|
1138
|
+
if (char === ',' && chevronsCount === 0) {
|
|
1139
|
+
parts.push(selector.substring(offset, i))
|
|
1140
|
+
offset = i + 1
|
|
1141
|
+
continue
|
|
1142
|
+
}
|
|
1143
|
+
if (char === '<') {
|
|
1144
|
+
chevronsCount++
|
|
1145
|
+
} else if (char === '/' && i < selector.length - 1 && selector[i + 1] === '>') {
|
|
1146
|
+
chevronsCount--
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (offset < selector.length) {
|
|
1150
|
+
parts.push(selector.substring(offset))
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
const result = []
|
|
1155
|
+
const unprocessedParts = []
|
|
1156
|
+
while (parts.length > 0) {
|
|
1157
|
+
const selector = normalizeSelector(parts.shift())
|
|
1158
|
+
let item
|
|
1159
|
+
if (selector.indexOf('closest ') === 0) {
|
|
1160
|
+
item = closest(asElement(elt), normalizeSelector(selector.slice(8)))
|
|
1161
|
+
} else if (selector.indexOf('find ') === 0) {
|
|
1162
|
+
item = find(asParentNode(elt), normalizeSelector(selector.slice(5)))
|
|
1163
|
+
} else if (selector === 'next' || selector === 'nextElementSibling') {
|
|
1164
|
+
item = asElement(elt).nextElementSibling
|
|
1165
|
+
} else if (selector.indexOf('next ') === 0) {
|
|
1166
|
+
item = scanForwardQuery(elt, normalizeSelector(selector.slice(5)), !!global)
|
|
1167
|
+
} else if (selector === 'previous' || selector === 'previousElementSibling') {
|
|
1168
|
+
item = asElement(elt).previousElementSibling
|
|
1169
|
+
} else if (selector.indexOf('previous ') === 0) {
|
|
1170
|
+
item = scanBackwardsQuery(elt, normalizeSelector(selector.slice(9)), !!global)
|
|
1171
|
+
} else if (selector === 'document') {
|
|
1172
|
+
item = document
|
|
1173
|
+
} else if (selector === 'window') {
|
|
1174
|
+
item = window
|
|
1175
|
+
} else if (selector === 'body') {
|
|
1176
|
+
item = document.body
|
|
1177
|
+
} else if (selector === 'root') {
|
|
1178
|
+
item = getRootNode(elt, !!global)
|
|
1179
|
+
} else if (selector === 'host') {
|
|
1180
|
+
item = (/** @type ShadowRoot */(elt.getRootNode())).host
|
|
1181
|
+
} else {
|
|
1182
|
+
unprocessedParts.push(selector)
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
if (item) {
|
|
1186
|
+
result.push(item)
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
if (unprocessedParts.length > 0) {
|
|
1191
|
+
const standardSelector = unprocessedParts.join(',')
|
|
1192
|
+
const rootNode = asParentNode(getRootNode(elt, !!global))
|
|
1193
|
+
result.push(...toArray(rootNode.querySelectorAll(standardSelector)))
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
return result
|
|
1159
1197
|
}
|
|
1160
1198
|
|
|
1161
1199
|
/**
|
|
@@ -1309,6 +1347,16 @@ var htmx = (function() {
|
|
|
1309
1347
|
return [findThisElement(elt, attrName)]
|
|
1310
1348
|
} else {
|
|
1311
1349
|
const result = querySelectorAllExt(elt, attrTarget)
|
|
1350
|
+
// find `inherit` whole word in value, make sure it's surrounded by commas or is at the start/end of string
|
|
1351
|
+
const shouldInherit = /(^|,)(\s*)inherit(\s*)($|,)/.test(attrTarget)
|
|
1352
|
+
if (shouldInherit) {
|
|
1353
|
+
const eltToInheritFrom = asElement(getClosestMatch(elt, function(parent) {
|
|
1354
|
+
return parent !== elt && hasAttribute(asElement(parent), attrName)
|
|
1355
|
+
}))
|
|
1356
|
+
if (eltToInheritFrom) {
|
|
1357
|
+
result.push(...findAttributeTargets(eltToInheritFrom, attrName))
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1312
1360
|
if (result.length === 0) {
|
|
1313
1361
|
logError('The selector "' + attrTarget + '" on ' + attrName + ' returned no matches!')
|
|
1314
1362
|
return [DUMMY_ELT]
|
|
@@ -1357,13 +1405,7 @@ var htmx = (function() {
|
|
|
1357
1405
|
* @returns {boolean}
|
|
1358
1406
|
*/
|
|
1359
1407
|
function shouldSettleAttribute(name) {
|
|
1360
|
-
|
|
1361
|
-
for (let i = 0; i < attributesToSettle.length; i++) {
|
|
1362
|
-
if (name === attributesToSettle[i]) {
|
|
1363
|
-
return true
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
return false
|
|
1408
|
+
return htmx.config.attributesToSettle.includes(name)
|
|
1367
1409
|
}
|
|
1368
1410
|
|
|
1369
1411
|
/**
|
|
@@ -1412,14 +1454,14 @@ var htmx = (function() {
|
|
|
1412
1454
|
*/
|
|
1413
1455
|
function oobSwap(oobValue, oobElement, settleInfo, rootNode) {
|
|
1414
1456
|
rootNode = rootNode || getDocument()
|
|
1415
|
-
let selector = '#' + getRawAttribute(oobElement, 'id')
|
|
1457
|
+
let selector = '#' + CSS.escape(getRawAttribute(oobElement, 'id'))
|
|
1416
1458
|
/** @type HtmxSwapStyle */
|
|
1417
1459
|
let swapStyle = 'outerHTML'
|
|
1418
1460
|
if (oobValue === 'true') {
|
|
1419
1461
|
// do nothing
|
|
1420
1462
|
} else if (oobValue.indexOf(':') > 0) {
|
|
1421
|
-
swapStyle = oobValue.
|
|
1422
|
-
selector = oobValue.
|
|
1463
|
+
swapStyle = oobValue.substring(0, oobValue.indexOf(':'))
|
|
1464
|
+
selector = oobValue.substring(oobValue.indexOf(':') + 1)
|
|
1423
1465
|
} else {
|
|
1424
1466
|
swapStyle = oobValue
|
|
1425
1467
|
}
|
|
@@ -1427,7 +1469,7 @@ var htmx = (function() {
|
|
|
1427
1469
|
oobElement.removeAttribute('data-hx-swap-oob')
|
|
1428
1470
|
|
|
1429
1471
|
const targets = querySelectorAllExt(rootNode, selector, false)
|
|
1430
|
-
if (targets) {
|
|
1472
|
+
if (targets.length) {
|
|
1431
1473
|
forEach(
|
|
1432
1474
|
targets,
|
|
1433
1475
|
function(target) {
|
|
@@ -1585,14 +1627,11 @@ var htmx = (function() {
|
|
|
1585
1627
|
*/
|
|
1586
1628
|
function attributeHash(elt) {
|
|
1587
1629
|
let hash = 0
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
hash = stringHash(attribute.name, hash)
|
|
1594
|
-
hash = stringHash(attribute.value, hash)
|
|
1595
|
-
}
|
|
1630
|
+
for (let i = 0; i < elt.attributes.length; i++) {
|
|
1631
|
+
const attribute = elt.attributes[i]
|
|
1632
|
+
if (attribute.value) { // only include attributes w/ actual values (empty is same as non-existent)
|
|
1633
|
+
hash = stringHash(attribute.name, hash)
|
|
1634
|
+
hash = stringHash(attribute.value, hash)
|
|
1596
1635
|
}
|
|
1597
1636
|
}
|
|
1598
1637
|
return hash
|
|
@@ -1628,7 +1667,7 @@ var htmx = (function() {
|
|
|
1628
1667
|
})
|
|
1629
1668
|
}
|
|
1630
1669
|
deInitOnHandlers(element)
|
|
1631
|
-
forEach(Object.keys(internalData), function(key) { delete internalData[key] })
|
|
1670
|
+
forEach(Object.keys(internalData), function(key) { if (key !== 'firstInitCompleted') delete internalData[key] })
|
|
1632
1671
|
}
|
|
1633
1672
|
|
|
1634
1673
|
/**
|
|
@@ -1637,21 +1676,17 @@ var htmx = (function() {
|
|
|
1637
1676
|
function cleanUpElement(element) {
|
|
1638
1677
|
triggerEvent(element, 'htmx:beforeCleanupElement')
|
|
1639
1678
|
deInitNode(element)
|
|
1640
|
-
// @ts-ignore
|
|
1641
|
-
|
|
1642
|
-
if (element.children) { // IE
|
|
1643
|
-
// @ts-ignore
|
|
1644
|
-
forEach(element.children, function(child) { cleanUpElement(child) })
|
|
1645
|
-
}
|
|
1679
|
+
// @ts-ignore
|
|
1680
|
+
forEach(element.children, function(child) { cleanUpElement(child) })
|
|
1646
1681
|
}
|
|
1647
1682
|
|
|
1648
1683
|
/**
|
|
1649
|
-
* @param {
|
|
1684
|
+
* @param {Element} target
|
|
1650
1685
|
* @param {ParentNode} fragment
|
|
1651
1686
|
* @param {HtmxSettleInfo} settleInfo
|
|
1652
1687
|
*/
|
|
1653
1688
|
function swapOuterHTML(target, fragment, settleInfo) {
|
|
1654
|
-
if (target
|
|
1689
|
+
if (target.tagName === 'BODY') { // special case the body to innerHTML because DocumentFragments can't contain a body elt unfortunately
|
|
1655
1690
|
return swapInnerHTML(target, fragment, settleInfo)
|
|
1656
1691
|
}
|
|
1657
1692
|
/** @type {Node} */
|
|
@@ -1677,15 +1712,11 @@ var htmx = (function() {
|
|
|
1677
1712
|
newElt = newElt.nextSibling
|
|
1678
1713
|
}
|
|
1679
1714
|
cleanUpElement(target)
|
|
1680
|
-
|
|
1681
|
-
target.remove()
|
|
1682
|
-
} else {
|
|
1683
|
-
target.parentNode.removeChild(target)
|
|
1684
|
-
}
|
|
1715
|
+
target.remove()
|
|
1685
1716
|
}
|
|
1686
1717
|
|
|
1687
1718
|
/**
|
|
1688
|
-
* @param {
|
|
1719
|
+
* @param {Element} target
|
|
1689
1720
|
* @param {ParentNode} fragment
|
|
1690
1721
|
* @param {HtmxSettleInfo} settleInfo
|
|
1691
1722
|
*/
|
|
@@ -1694,7 +1725,7 @@ var htmx = (function() {
|
|
|
1694
1725
|
}
|
|
1695
1726
|
|
|
1696
1727
|
/**
|
|
1697
|
-
* @param {
|
|
1728
|
+
* @param {Element} target
|
|
1698
1729
|
* @param {ParentNode} fragment
|
|
1699
1730
|
* @param {HtmxSettleInfo} settleInfo
|
|
1700
1731
|
*/
|
|
@@ -1703,7 +1734,7 @@ var htmx = (function() {
|
|
|
1703
1734
|
}
|
|
1704
1735
|
|
|
1705
1736
|
/**
|
|
1706
|
-
* @param {
|
|
1737
|
+
* @param {Element} target
|
|
1707
1738
|
* @param {ParentNode} fragment
|
|
1708
1739
|
* @param {HtmxSettleInfo} settleInfo
|
|
1709
1740
|
*/
|
|
@@ -1712,7 +1743,7 @@ var htmx = (function() {
|
|
|
1712
1743
|
}
|
|
1713
1744
|
|
|
1714
1745
|
/**
|
|
1715
|
-
* @param {
|
|
1746
|
+
* @param {Element} target
|
|
1716
1747
|
* @param {ParentNode} fragment
|
|
1717
1748
|
* @param {HtmxSettleInfo} settleInfo
|
|
1718
1749
|
*/
|
|
@@ -1721,7 +1752,7 @@ var htmx = (function() {
|
|
|
1721
1752
|
}
|
|
1722
1753
|
|
|
1723
1754
|
/**
|
|
1724
|
-
* @param {
|
|
1755
|
+
* @param {Element} target
|
|
1725
1756
|
*/
|
|
1726
1757
|
function swapDelete(target) {
|
|
1727
1758
|
cleanUpElement(target)
|
|
@@ -1732,7 +1763,7 @@ var htmx = (function() {
|
|
|
1732
1763
|
}
|
|
1733
1764
|
|
|
1734
1765
|
/**
|
|
1735
|
-
* @param {
|
|
1766
|
+
* @param {Element} target
|
|
1736
1767
|
* @param {ParentNode} fragment
|
|
1737
1768
|
* @param {HtmxSettleInfo} settleInfo
|
|
1738
1769
|
*/
|
|
@@ -1752,7 +1783,7 @@ var htmx = (function() {
|
|
|
1752
1783
|
/**
|
|
1753
1784
|
* @param {HtmxSwapStyle} swapStyle
|
|
1754
1785
|
* @param {Element} elt
|
|
1755
|
-
* @param {
|
|
1786
|
+
* @param {Element} target
|
|
1756
1787
|
* @param {ParentNode} fragment
|
|
1757
1788
|
* @param {HtmxSettleInfo} settleInfo
|
|
1758
1789
|
*/
|
|
@@ -1830,7 +1861,7 @@ var htmx = (function() {
|
|
|
1830
1861
|
}
|
|
1831
1862
|
|
|
1832
1863
|
/**
|
|
1833
|
-
* Implements complete swapping pipeline, including: focus and selection preservation,
|
|
1864
|
+
* Implements complete swapping pipeline, including: delay, view transitions, focus and selection preservation,
|
|
1834
1865
|
* title updates, scroll, OOB swapping, normal swapping and settling
|
|
1835
1866
|
* @param {string|Element} target
|
|
1836
1867
|
* @param {string} content
|
|
@@ -1841,14 +1872,19 @@ var htmx = (function() {
|
|
|
1841
1872
|
if (!swapOptions) {
|
|
1842
1873
|
swapOptions = {}
|
|
1843
1874
|
}
|
|
1875
|
+
// optional transition API promise callbacks
|
|
1876
|
+
let settleResolve = null
|
|
1877
|
+
let settleReject = null
|
|
1844
1878
|
|
|
1845
|
-
|
|
1846
|
-
|
|
1879
|
+
let doSwap = function() {
|
|
1880
|
+
maybeCall(swapOptions.beforeSwapCallback)
|
|
1847
1881
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1882
|
+
target = resolveTarget(target)
|
|
1883
|
+
const rootNode = swapOptions.contextElement ? getRootNode(swapOptions.contextElement, false) : getDocument()
|
|
1884
|
+
|
|
1885
|
+
// preserve focus and selection
|
|
1886
|
+
const activeElt = document.activeElement
|
|
1887
|
+
let selectionInfo = {}
|
|
1852
1888
|
selectionInfo = {
|
|
1853
1889
|
elt: activeElt,
|
|
1854
1890
|
// @ts-ignore
|
|
@@ -1856,123 +1892,160 @@ var htmx = (function() {
|
|
|
1856
1892
|
// @ts-ignore
|
|
1857
1893
|
end: activeElt ? activeElt.selectionEnd : null
|
|
1858
1894
|
}
|
|
1859
|
-
|
|
1860
|
-
// safari issue - see https://github.com/microsoft/playwright/issues/5894
|
|
1861
|
-
}
|
|
1862
|
-
const settleInfo = makeSettleInfo(target)
|
|
1895
|
+
const settleInfo = makeSettleInfo(target)
|
|
1863
1896
|
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1897
|
+
// For text content swaps, don't parse the response as HTML, just insert it
|
|
1898
|
+
if (swapSpec.swapStyle === 'textContent') {
|
|
1899
|
+
target.textContent = content
|
|
1900
|
+
// Otherwise, make the fragment and process it
|
|
1901
|
+
} else {
|
|
1902
|
+
let fragment = makeFragment(content)
|
|
1903
|
+
|
|
1904
|
+
settleInfo.title = swapOptions.title || fragment.title
|
|
1905
|
+
if (swapOptions.historyRequest) {
|
|
1906
|
+
// @ts-ignore fragment can be a parentNode Element
|
|
1907
|
+
fragment = fragment.querySelector('[hx-history-elt],[data-hx-history-elt]') || fragment
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
// select-oob swaps
|
|
1911
|
+
if (swapOptions.selectOOB) {
|
|
1912
|
+
const oobSelectValues = swapOptions.selectOOB.split(',')
|
|
1913
|
+
for (let i = 0; i < oobSelectValues.length; i++) {
|
|
1914
|
+
const oobSelectValue = oobSelectValues[i].split(':', 2)
|
|
1915
|
+
let id = oobSelectValue[0].trim()
|
|
1916
|
+
if (id.indexOf('#') === 0) {
|
|
1917
|
+
id = id.substring(1)
|
|
1918
|
+
}
|
|
1919
|
+
const oobValue = oobSelectValue[1] || 'true'
|
|
1920
|
+
const oobElement = fragment.querySelector('#' + id)
|
|
1921
|
+
if (oobElement) {
|
|
1922
|
+
oobSwap(oobValue, oobElement, settleInfo, rootNode)
|
|
1923
|
+
}
|
|
1881
1924
|
}
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1925
|
+
}
|
|
1926
|
+
// oob swaps
|
|
1927
|
+
findAndSwapOobElements(fragment, settleInfo, rootNode)
|
|
1928
|
+
forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) {
|
|
1929
|
+
if (template.content && findAndSwapOobElements(template.content, settleInfo, rootNode)) {
|
|
1930
|
+
// Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap
|
|
1931
|
+
template.remove()
|
|
1886
1932
|
}
|
|
1933
|
+
})
|
|
1934
|
+
|
|
1935
|
+
// normal swap
|
|
1936
|
+
if (swapOptions.select) {
|
|
1937
|
+
const newFragment = getDocument().createDocumentFragment()
|
|
1938
|
+
forEach(fragment.querySelectorAll(swapOptions.select), function(node) {
|
|
1939
|
+
newFragment.appendChild(node)
|
|
1940
|
+
})
|
|
1941
|
+
fragment = newFragment
|
|
1942
|
+
}
|
|
1943
|
+
handlePreservedElements(fragment)
|
|
1944
|
+
swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo)
|
|
1945
|
+
restorePreservedElements()
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
// apply saved focus and selection information to swapped content
|
|
1949
|
+
if (selectionInfo.elt &&
|
|
1950
|
+
!bodyContains(selectionInfo.elt) &&
|
|
1951
|
+
getRawAttribute(selectionInfo.elt, 'id')) {
|
|
1952
|
+
const newActiveElt = document.getElementById(getRawAttribute(selectionInfo.elt, 'id'))
|
|
1953
|
+
const focusOptions = { preventScroll: swapSpec.focusScroll !== undefined ? !swapSpec.focusScroll : !htmx.config.defaultFocusScroll }
|
|
1954
|
+
if (newActiveElt) {
|
|
1955
|
+
// @ts-ignore
|
|
1956
|
+
if (selectionInfo.start && newActiveElt.setSelectionRange) {
|
|
1957
|
+
try {
|
|
1958
|
+
// @ts-ignore
|
|
1959
|
+
newActiveElt.setSelectionRange(selectionInfo.start, selectionInfo.end)
|
|
1960
|
+
} catch (e) {
|
|
1961
|
+
// the setSelectionRange method is present on fields that don't support it, so just let this fail
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
newActiveElt.focus(focusOptions)
|
|
1887
1965
|
}
|
|
1888
1966
|
}
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
forEach(
|
|
1892
|
-
if (
|
|
1893
|
-
|
|
1894
|
-
template.remove()
|
|
1967
|
+
|
|
1968
|
+
target.classList.remove(htmx.config.swappingClass)
|
|
1969
|
+
forEach(settleInfo.elts, function(elt) {
|
|
1970
|
+
if (elt.classList) {
|
|
1971
|
+
elt.classList.add(htmx.config.settlingClass)
|
|
1895
1972
|
}
|
|
1973
|
+
triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo)
|
|
1896
1974
|
})
|
|
1975
|
+
maybeCall(swapOptions.afterSwapCallback)
|
|
1897
1976
|
|
|
1898
|
-
//
|
|
1899
|
-
if (
|
|
1900
|
-
|
|
1901
|
-
forEach(fragment.querySelectorAll(swapOptions.select), function(node) {
|
|
1902
|
-
newFragment.appendChild(node)
|
|
1903
|
-
})
|
|
1904
|
-
fragment = newFragment
|
|
1977
|
+
// merge in new title after swap but before settle
|
|
1978
|
+
if (!swapSpec.ignoreTitle) {
|
|
1979
|
+
handleTitle(settleInfo.title)
|
|
1905
1980
|
}
|
|
1906
|
-
handlePreservedElements(fragment)
|
|
1907
|
-
swapWithStyle(swapSpec.swapStyle, swapOptions.contextElement, target, fragment, settleInfo)
|
|
1908
|
-
restorePreservedElements()
|
|
1909
|
-
}
|
|
1910
1981
|
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1982
|
+
// settle
|
|
1983
|
+
const doSettle = function() {
|
|
1984
|
+
forEach(settleInfo.tasks, function(task) {
|
|
1985
|
+
task.call()
|
|
1986
|
+
})
|
|
1987
|
+
forEach(settleInfo.elts, function(elt) {
|
|
1988
|
+
if (elt.classList) {
|
|
1989
|
+
elt.classList.remove(htmx.config.settlingClass)
|
|
1990
|
+
}
|
|
1991
|
+
triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo)
|
|
1992
|
+
})
|
|
1993
|
+
|
|
1994
|
+
if (swapOptions.anchor) {
|
|
1995
|
+
const anchorTarget = asElement(resolveTarget('#' + swapOptions.anchor))
|
|
1996
|
+
if (anchorTarget) {
|
|
1997
|
+
anchorTarget.scrollIntoView({ block: 'start', behavior: 'auto' })
|
|
1925
1998
|
}
|
|
1926
1999
|
}
|
|
1927
|
-
|
|
2000
|
+
|
|
2001
|
+
updateScrollState(settleInfo.elts, swapSpec)
|
|
2002
|
+
maybeCall(swapOptions.afterSettleCallback)
|
|
2003
|
+
maybeCall(settleResolve)
|
|
1928
2004
|
}
|
|
1929
|
-
}
|
|
1930
2005
|
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
2006
|
+
if (swapSpec.settleDelay > 0) {
|
|
2007
|
+
getWindow().setTimeout(doSettle, swapSpec.settleDelay)
|
|
2008
|
+
} else {
|
|
2009
|
+
doSettle()
|
|
1935
2010
|
}
|
|
1936
|
-
triggerEvent(elt, 'htmx:afterSwap', swapOptions.eventInfo)
|
|
1937
|
-
})
|
|
1938
|
-
if (swapOptions.afterSwapCallback) {
|
|
1939
|
-
swapOptions.afterSwapCallback()
|
|
1940
2011
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
handleTitle(settleInfo.title)
|
|
2012
|
+
let shouldTransition = htmx.config.globalViewTransitions
|
|
2013
|
+
if (swapSpec.hasOwnProperty('transition')) {
|
|
2014
|
+
shouldTransition = swapSpec.transition
|
|
1945
2015
|
}
|
|
1946
2016
|
|
|
1947
|
-
|
|
1948
|
-
const doSettle = function() {
|
|
1949
|
-
forEach(settleInfo.tasks, function(task) {
|
|
1950
|
-
task.call()
|
|
1951
|
-
})
|
|
1952
|
-
forEach(settleInfo.elts, function(elt) {
|
|
1953
|
-
if (elt.classList) {
|
|
1954
|
-
elt.classList.remove(htmx.config.settlingClass)
|
|
1955
|
-
}
|
|
1956
|
-
triggerEvent(elt, 'htmx:afterSettle', swapOptions.eventInfo)
|
|
1957
|
-
})
|
|
2017
|
+
const elt = swapOptions.contextElement || getDocument()
|
|
1958
2018
|
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2019
|
+
if (shouldTransition &&
|
|
2020
|
+
triggerEvent(elt, 'htmx:beforeTransition', swapOptions.eventInfo) &&
|
|
2021
|
+
typeof Promise !== 'undefined' &&
|
|
2022
|
+
// @ts-ignore experimental feature atm
|
|
2023
|
+
document.startViewTransition) {
|
|
2024
|
+
const settlePromise = new Promise(function(_resolve, _reject) {
|
|
2025
|
+
settleResolve = _resolve
|
|
2026
|
+
settleReject = _reject
|
|
2027
|
+
})
|
|
2028
|
+
// wrap the original doSwap() in a call to startViewTransition()
|
|
2029
|
+
const innerDoSwap = doSwap
|
|
2030
|
+
doSwap = function() {
|
|
2031
|
+
// @ts-ignore experimental feature atm
|
|
2032
|
+
document.startViewTransition(function() {
|
|
2033
|
+
innerDoSwap()
|
|
2034
|
+
return settlePromise
|
|
2035
|
+
})
|
|
1969
2036
|
}
|
|
1970
2037
|
}
|
|
1971
2038
|
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
2039
|
+
try {
|
|
2040
|
+
if (swapSpec?.swapDelay && swapSpec.swapDelay > 0) {
|
|
2041
|
+
getWindow().setTimeout(doSwap, swapSpec.swapDelay)
|
|
2042
|
+
} else {
|
|
2043
|
+
doSwap()
|
|
2044
|
+
}
|
|
2045
|
+
} catch (e) {
|
|
2046
|
+
triggerErrorEvent(elt, 'htmx:swapError', swapOptions.eventInfo)
|
|
2047
|
+
maybeCall(settleReject)
|
|
2048
|
+
throw e
|
|
1976
2049
|
}
|
|
1977
2050
|
}
|
|
1978
2051
|
|
|
@@ -2028,7 +2101,7 @@ var htmx = (function() {
|
|
|
2028
2101
|
while (SYMBOL_CONT.exec(str.charAt(position + 1))) {
|
|
2029
2102
|
position++
|
|
2030
2103
|
}
|
|
2031
|
-
tokens.push(str.
|
|
2104
|
+
tokens.push(str.substring(startPosition, position + 1))
|
|
2032
2105
|
} else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) {
|
|
2033
2106
|
const startChar = str.charAt(position)
|
|
2034
2107
|
var startPosition = position
|
|
@@ -2039,7 +2112,7 @@ var htmx = (function() {
|
|
|
2039
2112
|
}
|
|
2040
2113
|
position++
|
|
2041
2114
|
}
|
|
2042
|
-
tokens.push(str.
|
|
2115
|
+
tokens.push(str.substring(startPosition, position + 1))
|
|
2043
2116
|
} else {
|
|
2044
2117
|
const symbol = str.charAt(position)
|
|
2045
2118
|
tokens.push(symbol)
|
|
@@ -2323,6 +2396,11 @@ var htmx = (function() {
|
|
|
2323
2396
|
const rawAttribute = getRawAttribute(elt, 'method')
|
|
2324
2397
|
verb = (/** @type HttpVerb */(rawAttribute ? rawAttribute.toLowerCase() : 'get'))
|
|
2325
2398
|
path = getRawAttribute(elt, 'action')
|
|
2399
|
+
if (path == null || path === '') {
|
|
2400
|
+
// if there is no action attribute on the form set path to current href before the
|
|
2401
|
+
// following logic to properly clear parameters on a GET (not on a POST!)
|
|
2402
|
+
path = location.href
|
|
2403
|
+
}
|
|
2326
2404
|
if (verb === 'get' && path.includes('?')) {
|
|
2327
2405
|
path = path.replace(/\?[^#]+/, '')
|
|
2328
2406
|
}
|
|
@@ -2342,19 +2420,19 @@ var htmx = (function() {
|
|
|
2342
2420
|
|
|
2343
2421
|
/**
|
|
2344
2422
|
* @param {Event} evt
|
|
2345
|
-
* @param {
|
|
2423
|
+
* @param {Element} elt
|
|
2346
2424
|
* @returns {boolean}
|
|
2347
2425
|
*/
|
|
2348
|
-
function shouldCancel(evt,
|
|
2349
|
-
const elt = asElement(node)
|
|
2350
|
-
if (!elt) {
|
|
2351
|
-
return false
|
|
2352
|
-
}
|
|
2426
|
+
function shouldCancel(evt, elt) {
|
|
2353
2427
|
if (evt.type === 'submit' || evt.type === 'click') {
|
|
2428
|
+
// use elt from event that was submitted/clicked where possible to determining if default form/link behavior should be canceled
|
|
2429
|
+
elt = asElement(evt.target) || elt
|
|
2354
2430
|
if (elt.tagName === 'FORM') {
|
|
2355
2431
|
return true
|
|
2356
2432
|
}
|
|
2357
|
-
|
|
2433
|
+
// @ts-ignore Do not cancel on buttons that 1) don't have a related form or 2) have a type attribute of 'reset'/'button'.
|
|
2434
|
+
// The properties will resolve to undefined for elements that don't define 'type' or 'form', which is fine
|
|
2435
|
+
if (elt.form && elt.type === 'submit') {
|
|
2358
2436
|
return true
|
|
2359
2437
|
}
|
|
2360
2438
|
if (elt instanceof HTMLAnchorElement && elt.href &&
|
|
@@ -2397,7 +2475,7 @@ var htmx = (function() {
|
|
|
2397
2475
|
}
|
|
2398
2476
|
|
|
2399
2477
|
/**
|
|
2400
|
-
* @param {
|
|
2478
|
+
* @param {Element} elt
|
|
2401
2479
|
* @param {TriggerHandler} handler
|
|
2402
2480
|
* @param {HtmxNodeInternalData} nodeData
|
|
2403
2481
|
* @param {HtmxTriggerSpecification} triggerSpec
|
|
@@ -2464,7 +2542,7 @@ var htmx = (function() {
|
|
|
2464
2542
|
}
|
|
2465
2543
|
}
|
|
2466
2544
|
if (triggerSpec.changed) {
|
|
2467
|
-
const node =
|
|
2545
|
+
const node = evt.target
|
|
2468
2546
|
// @ts-ignore value will be undefined for non-input elements, which is fine
|
|
2469
2547
|
const value = node.value
|
|
2470
2548
|
const lastValue = elementData.lastValue.get(triggerSpec)
|
|
@@ -2559,6 +2637,7 @@ var htmx = (function() {
|
|
|
2559
2637
|
const load = function() {
|
|
2560
2638
|
if (!nodeData.loaded) {
|
|
2561
2639
|
nodeData.loaded = true
|
|
2640
|
+
triggerEvent(elt, 'htmx:trigger')
|
|
2562
2641
|
handler(elt)
|
|
2563
2642
|
}
|
|
2564
2643
|
}
|
|
@@ -2586,7 +2665,7 @@ var htmx = (function() {
|
|
|
2586
2665
|
triggerSpecs.forEach(function(triggerSpec) {
|
|
2587
2666
|
addTriggerHandler(elt, triggerSpec, nodeData, function(node, evt) {
|
|
2588
2667
|
const elt = asElement(node)
|
|
2589
|
-
if (
|
|
2668
|
+
if (eltIsDisabled(elt)) {
|
|
2590
2669
|
cleanUpElement(elt)
|
|
2591
2670
|
return
|
|
2592
2671
|
}
|
|
@@ -2600,12 +2679,12 @@ var htmx = (function() {
|
|
|
2600
2679
|
|
|
2601
2680
|
/**
|
|
2602
2681
|
* @callback TriggerHandler
|
|
2603
|
-
* @param {
|
|
2682
|
+
* @param {Element} elt
|
|
2604
2683
|
* @param {Event} [evt]
|
|
2605
2684
|
*/
|
|
2606
2685
|
|
|
2607
2686
|
/**
|
|
2608
|
-
* @param {
|
|
2687
|
+
* @param {Element} elt
|
|
2609
2688
|
* @param {HtmxTriggerSpecification} triggerSpec
|
|
2610
2689
|
* @param {HtmxNodeInternalData} nodeData
|
|
2611
2690
|
* @param {TriggerHandler} handler
|
|
@@ -2634,7 +2713,7 @@ var htmx = (function() {
|
|
|
2634
2713
|
}, observerOptions)
|
|
2635
2714
|
observer.observe(asElement(elt))
|
|
2636
2715
|
addEventListener(asElement(elt), handler, nodeData, triggerSpec)
|
|
2637
|
-
} else if (triggerSpec.trigger === 'load') {
|
|
2716
|
+
} else if (!nodeData.firstInitCompleted && triggerSpec.trigger === 'load') {
|
|
2638
2717
|
if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) {
|
|
2639
2718
|
loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay)
|
|
2640
2719
|
}
|
|
@@ -2730,7 +2809,7 @@ var htmx = (function() {
|
|
|
2730
2809
|
* @param {Event} evt
|
|
2731
2810
|
*/
|
|
2732
2811
|
function maybeSetLastButtonClicked(evt) {
|
|
2733
|
-
const elt =
|
|
2812
|
+
const elt = getTargetButton(evt.target)
|
|
2734
2813
|
const internalData = getRelatedFormData(evt)
|
|
2735
2814
|
if (internalData) {
|
|
2736
2815
|
internalData.lastButtonClicked = elt
|
|
@@ -2747,19 +2826,33 @@ var htmx = (function() {
|
|
|
2747
2826
|
}
|
|
2748
2827
|
}
|
|
2749
2828
|
|
|
2829
|
+
/**
|
|
2830
|
+
* @param {EventTarget} target
|
|
2831
|
+
* @returns {HTMLButtonElement|HTMLInputElement|null}
|
|
2832
|
+
*/
|
|
2833
|
+
function getTargetButton(target) {
|
|
2834
|
+
return /** @type {HTMLButtonElement|HTMLInputElement|null} */ (closest(asElement(target), "button, input[type='submit']"))
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
/**
|
|
2838
|
+
* @param {Element} elt
|
|
2839
|
+
* @returns {HTMLFormElement|null}
|
|
2840
|
+
*/
|
|
2841
|
+
function getRelatedForm(elt) {
|
|
2842
|
+
// @ts-ignore Get the related form if available, else find the closest parent form
|
|
2843
|
+
return elt.form || closest(elt, 'form')
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2750
2846
|
/**
|
|
2751
2847
|
* @param {Event} evt
|
|
2752
2848
|
* @returns {HtmxNodeInternalData|undefined}
|
|
2753
2849
|
*/
|
|
2754
2850
|
function getRelatedFormData(evt) {
|
|
2755
|
-
const elt =
|
|
2851
|
+
const elt = getTargetButton(evt.target)
|
|
2756
2852
|
if (!elt) {
|
|
2757
2853
|
return
|
|
2758
2854
|
}
|
|
2759
|
-
const form =
|
|
2760
|
-
if (!form) {
|
|
2761
|
-
return
|
|
2762
|
-
}
|
|
2855
|
+
const form = getRelatedForm(elt)
|
|
2763
2856
|
return getInternalData(form)
|
|
2764
2857
|
}
|
|
2765
2858
|
|
|
@@ -2836,42 +2929,52 @@ var htmx = (function() {
|
|
|
2836
2929
|
* @param {Element|HTMLInputElement} elt
|
|
2837
2930
|
*/
|
|
2838
2931
|
function initNode(elt) {
|
|
2839
|
-
|
|
2840
|
-
cleanUpElement(elt)
|
|
2841
|
-
return
|
|
2842
|
-
}
|
|
2843
|
-
const nodeData = getInternalData(elt)
|
|
2844
|
-
if (nodeData.initHash !== attributeHash(elt)) {
|
|
2845
|
-
// clean up any previously processed info
|
|
2846
|
-
deInitNode(elt)
|
|
2932
|
+
triggerEvent(elt, 'htmx:beforeProcessNode')
|
|
2847
2933
|
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
const triggerSpecs = getTriggerSpecs(elt)
|
|
2853
|
-
const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs)
|
|
2934
|
+
const nodeData = getInternalData(elt)
|
|
2935
|
+
const triggerSpecs = getTriggerSpecs(elt)
|
|
2936
|
+
const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs)
|
|
2854
2937
|
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
})
|
|
2938
|
+
if (!hasExplicitHttpAction) {
|
|
2939
|
+
if (getClosestAttributeValue(elt, 'hx-boost') === 'true') {
|
|
2940
|
+
boostElement(elt, nodeData, triggerSpecs)
|
|
2941
|
+
} else if (hasAttribute(elt, 'hx-trigger')) {
|
|
2942
|
+
triggerSpecs.forEach(function(triggerSpec) {
|
|
2943
|
+
// For "naked" triggers, don't do anything at all
|
|
2944
|
+
addTriggerHandler(elt, triggerSpec, nodeData, function() {
|
|
2863
2945
|
})
|
|
2864
|
-
}
|
|
2946
|
+
})
|
|
2865
2947
|
}
|
|
2948
|
+
}
|
|
2866
2949
|
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2950
|
+
// Handle submit buttons/inputs that have the form attribute set
|
|
2951
|
+
// see https://developer.mozilla.org/docs/Web/HTML/Element/button
|
|
2952
|
+
if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) {
|
|
2953
|
+
initButtonTracking(elt)
|
|
2954
|
+
}
|
|
2872
2955
|
|
|
2873
|
-
|
|
2956
|
+
nodeData.firstInitCompleted = true
|
|
2957
|
+
triggerEvent(elt, 'htmx:afterProcessNode')
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
/**
|
|
2961
|
+
* @param {Element} elt
|
|
2962
|
+
* @returns {boolean}
|
|
2963
|
+
*/
|
|
2964
|
+
function maybeDeInitAndHash(elt) {
|
|
2965
|
+
// Ensure only valid Elements and not shadow DOM roots are inited
|
|
2966
|
+
if (!(elt instanceof Element)) {
|
|
2967
|
+
return false
|
|
2874
2968
|
}
|
|
2969
|
+
|
|
2970
|
+
const nodeData = getInternalData(elt)
|
|
2971
|
+
const hash = attributeHash(elt)
|
|
2972
|
+
if (nodeData.initHash !== hash) {
|
|
2973
|
+
deInitNode(elt)
|
|
2974
|
+
nodeData.initHash = hash
|
|
2975
|
+
return true
|
|
2976
|
+
}
|
|
2977
|
+
return false
|
|
2875
2978
|
}
|
|
2876
2979
|
|
|
2877
2980
|
/**
|
|
@@ -2883,13 +2986,27 @@ var htmx = (function() {
|
|
|
2883
2986
|
*/
|
|
2884
2987
|
function processNode(elt) {
|
|
2885
2988
|
elt = resolveTarget(elt)
|
|
2886
|
-
if (
|
|
2989
|
+
if (eltIsDisabled(elt)) {
|
|
2887
2990
|
cleanUpElement(elt)
|
|
2888
2991
|
return
|
|
2889
2992
|
}
|
|
2890
|
-
|
|
2891
|
-
|
|
2993
|
+
|
|
2994
|
+
const elementsToInit = []
|
|
2995
|
+
if (maybeDeInitAndHash(elt)) {
|
|
2996
|
+
elementsToInit.push(elt)
|
|
2997
|
+
}
|
|
2998
|
+
forEach(findElementsToProcess(elt), function(child) {
|
|
2999
|
+
if (eltIsDisabled(child)) {
|
|
3000
|
+
cleanUpElement(child)
|
|
3001
|
+
return
|
|
3002
|
+
}
|
|
3003
|
+
if (maybeDeInitAndHash(child)) {
|
|
3004
|
+
elementsToInit.push(child)
|
|
3005
|
+
}
|
|
3006
|
+
})
|
|
3007
|
+
|
|
2892
3008
|
forEach(findHxOnWildcardElements(elt), processHxOnWildcard)
|
|
3009
|
+
forEach(elementsToInit, initNode)
|
|
2893
3010
|
}
|
|
2894
3011
|
|
|
2895
3012
|
//= ===================================================================
|
|
@@ -2910,16 +3027,9 @@ var htmx = (function() {
|
|
|
2910
3027
|
* @returns {CustomEvent}
|
|
2911
3028
|
*/
|
|
2912
3029
|
function makeEvent(eventName, detail) {
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
// This breaks expected encapsulation but needs to be here until decided otherwise by core devs
|
|
2917
|
-
evt = new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail })
|
|
2918
|
-
} else {
|
|
2919
|
-
evt = getDocument().createEvent('CustomEvent')
|
|
2920
|
-
evt.initCustomEvent(eventName, true, true, detail)
|
|
2921
|
-
}
|
|
2922
|
-
return evt
|
|
3030
|
+
// TODO: `composed: true` here is a hack to make global event handlers work with events in shadow DOM
|
|
3031
|
+
// This breaks expected encapsulation but needs to be here until decided otherwise by core devs
|
|
3032
|
+
return new CustomEvent(eventName, { bubbles: true, cancelable: true, composed: true, detail })
|
|
2923
3033
|
}
|
|
2924
3034
|
|
|
2925
3035
|
/**
|
|
@@ -2941,15 +3051,17 @@ var htmx = (function() {
|
|
|
2941
3051
|
|
|
2942
3052
|
/**
|
|
2943
3053
|
* `withExtensions` locates all active extensions for a provided element, then
|
|
2944
|
-
* executes the provided function using each of the active extensions.
|
|
3054
|
+
* executes the provided function using each of the active extensions. You can filter
|
|
3055
|
+
* the element's extensions by giving it a list of extensions to ignore. It should
|
|
2945
3056
|
* be called internally at every extendable execution point in htmx.
|
|
2946
3057
|
*
|
|
2947
3058
|
* @param {Element} elt
|
|
2948
3059
|
* @param {(extension:HtmxExtension) => void} toDo
|
|
3060
|
+
* @param {string[]=} extensionsToIgnore
|
|
2949
3061
|
* @returns void
|
|
2950
3062
|
*/
|
|
2951
|
-
function withExtensions(elt, toDo) {
|
|
2952
|
-
forEach(getExtensions(elt), function(extension) {
|
|
3063
|
+
function withExtensions(elt, toDo, extensionsToIgnore) {
|
|
3064
|
+
forEach(getExtensions(elt, [], extensionsToIgnore), function(extension) {
|
|
2953
3065
|
try {
|
|
2954
3066
|
toDo(extension)
|
|
2955
3067
|
} catch (e) {
|
|
@@ -2959,11 +3071,7 @@ var htmx = (function() {
|
|
|
2959
3071
|
}
|
|
2960
3072
|
|
|
2961
3073
|
function logError(msg) {
|
|
2962
|
-
|
|
2963
|
-
console.error(msg)
|
|
2964
|
-
} else if (console.log) {
|
|
2965
|
-
console.log('ERROR: ', msg)
|
|
2966
|
-
}
|
|
3074
|
+
console.error(msg)
|
|
2967
3075
|
}
|
|
2968
3076
|
|
|
2969
3077
|
/**
|
|
@@ -3007,6 +3115,16 @@ var htmx = (function() {
|
|
|
3007
3115
|
//= ===================================================================
|
|
3008
3116
|
let currentPathForHistory = location.pathname + location.search
|
|
3009
3117
|
|
|
3118
|
+
/**
|
|
3119
|
+
* @param {string} path
|
|
3120
|
+
*/
|
|
3121
|
+
function setCurrentPathForHistory(path) {
|
|
3122
|
+
currentPathForHistory = path
|
|
3123
|
+
if (canAccessLocalStorage()) {
|
|
3124
|
+
sessionStorage.setItem('htmx-current-path-for-history', path)
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3010
3128
|
/**
|
|
3011
3129
|
* @returns {Element}
|
|
3012
3130
|
*/
|
|
@@ -3031,13 +3149,13 @@ var htmx = (function() {
|
|
|
3031
3149
|
|
|
3032
3150
|
if (htmx.config.historyCacheSize <= 0) {
|
|
3033
3151
|
// make sure that an eventually already existing cache is purged
|
|
3034
|
-
|
|
3152
|
+
sessionStorage.removeItem('htmx-history-cache')
|
|
3035
3153
|
return
|
|
3036
3154
|
}
|
|
3037
3155
|
|
|
3038
3156
|
url = normalizePath(url)
|
|
3039
3157
|
|
|
3040
|
-
const historyCache = parseJSON(
|
|
3158
|
+
const historyCache = parseJSON(sessionStorage.getItem('htmx-history-cache')) || []
|
|
3041
3159
|
for (let i = 0; i < historyCache.length; i++) {
|
|
3042
3160
|
if (historyCache[i].url === url) {
|
|
3043
3161
|
historyCache.splice(i, 1)
|
|
@@ -3058,7 +3176,7 @@ var htmx = (function() {
|
|
|
3058
3176
|
// keep trying to save the cache until it succeeds or is empty
|
|
3059
3177
|
while (historyCache.length > 0) {
|
|
3060
3178
|
try {
|
|
3061
|
-
|
|
3179
|
+
sessionStorage.setItem('htmx-history-cache', JSON.stringify(historyCache))
|
|
3062
3180
|
break
|
|
3063
3181
|
} catch (e) {
|
|
3064
3182
|
triggerErrorEvent(getDocument().body, 'htmx:historyCacheError', { cause: e, cache: historyCache })
|
|
@@ -3086,7 +3204,7 @@ var htmx = (function() {
|
|
|
3086
3204
|
|
|
3087
3205
|
url = normalizePath(url)
|
|
3088
3206
|
|
|
3089
|
-
const historyCache = parseJSON(
|
|
3207
|
+
const historyCache = parseJSON(sessionStorage.getItem('htmx-history-cache')) || []
|
|
3090
3208
|
for (let i = 0; i < historyCache.length; i++) {
|
|
3091
3209
|
if (historyCache[i].url === url) {
|
|
3092
3210
|
return historyCache[i]
|
|
@@ -3114,26 +3232,24 @@ var htmx = (function() {
|
|
|
3114
3232
|
|
|
3115
3233
|
function saveCurrentPageToHistory() {
|
|
3116
3234
|
const elt = getHistoryElement()
|
|
3117
|
-
|
|
3235
|
+
let path = currentPathForHistory
|
|
3236
|
+
if (canAccessLocalStorage()) {
|
|
3237
|
+
path = sessionStorage.getItem('htmx-current-path-for-history')
|
|
3238
|
+
}
|
|
3239
|
+
path = path || location.pathname + location.search
|
|
3118
3240
|
|
|
3119
3241
|
// Allow history snapshot feature to be disabled where hx-history="false"
|
|
3120
3242
|
// is present *anywhere* in the current document we're about to save,
|
|
3121
3243
|
// so we can prevent privileged data entering the cache.
|
|
3122
3244
|
// The page will still be reachable as a history entry, but htmx will fetch it
|
|
3123
|
-
// live from the server onpopstate rather than look in the
|
|
3124
|
-
|
|
3125
|
-
try {
|
|
3126
|
-
disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]')
|
|
3127
|
-
} catch (e) {
|
|
3128
|
-
// IE11: insensitive modifier not supported so fallback to case sensitive selector
|
|
3129
|
-
disableHistoryCache = getDocument().querySelector('[hx-history="false"],[data-hx-history="false"]')
|
|
3130
|
-
}
|
|
3245
|
+
// live from the server onpopstate rather than look in the sessionStorage cache
|
|
3246
|
+
const disableHistoryCache = getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]')
|
|
3131
3247
|
if (!disableHistoryCache) {
|
|
3132
3248
|
triggerEvent(getDocument().body, 'htmx:beforeHistorySave', { path, historyElt: elt })
|
|
3133
3249
|
saveToHistoryCache(path, elt)
|
|
3134
3250
|
}
|
|
3135
3251
|
|
|
3136
|
-
if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title,
|
|
3252
|
+
if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, getDocument().title, location.href)
|
|
3137
3253
|
}
|
|
3138
3254
|
|
|
3139
3255
|
/**
|
|
@@ -3150,7 +3266,7 @@ var htmx = (function() {
|
|
|
3150
3266
|
if (htmx.config.historyEnabled) {
|
|
3151
3267
|
history.pushState({ htmx: true }, '', path)
|
|
3152
3268
|
}
|
|
3153
|
-
|
|
3269
|
+
setCurrentPathForHistory(path)
|
|
3154
3270
|
}
|
|
3155
3271
|
|
|
3156
3272
|
/**
|
|
@@ -3158,7 +3274,7 @@ var htmx = (function() {
|
|
|
3158
3274
|
*/
|
|
3159
3275
|
function replaceUrlInHistory(path) {
|
|
3160
3276
|
if (htmx.config.historyEnabled) history.replaceState({ htmx: true }, '', path)
|
|
3161
|
-
|
|
3277
|
+
setCurrentPathForHistory(path)
|
|
3162
3278
|
}
|
|
3163
3279
|
|
|
3164
3280
|
/**
|
|
@@ -3175,33 +3291,31 @@ var htmx = (function() {
|
|
|
3175
3291
|
*/
|
|
3176
3292
|
function loadHistoryFromServer(path) {
|
|
3177
3293
|
const request = new XMLHttpRequest()
|
|
3178
|
-
const
|
|
3179
|
-
|
|
3294
|
+
const swapSpec = { swapStyle: 'innerHTML', swapDelay: 0, settleDelay: 0 }
|
|
3295
|
+
const details = { path, xhr: request, historyElt: getHistoryElement(), swapSpec }
|
|
3180
3296
|
request.open('GET', path, true)
|
|
3181
|
-
|
|
3297
|
+
if (htmx.config.historyRestoreAsHxRequest) {
|
|
3298
|
+
request.setRequestHeader('HX-Request', 'true')
|
|
3299
|
+
}
|
|
3182
3300
|
request.setRequestHeader('HX-History-Restore-Request', 'true')
|
|
3183
|
-
request.setRequestHeader('HX-Current-URL',
|
|
3301
|
+
request.setRequestHeader('HX-Current-URL', location.href)
|
|
3184
3302
|
request.onload = function() {
|
|
3185
3303
|
if (this.status >= 200 && this.status < 400) {
|
|
3304
|
+
details.response = this.response
|
|
3186
3305
|
triggerEvent(getDocument().body, 'htmx:historyCacheMissLoad', details)
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
handlePreservedElements(fragment)
|
|
3195
|
-
swapInnerHTML(historyElement, content, settleInfo)
|
|
3196
|
-
restorePreservedElements()
|
|
3197
|
-
settleImmediately(settleInfo.tasks)
|
|
3198
|
-
currentPathForHistory = path
|
|
3199
|
-
triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: this.response })
|
|
3306
|
+
swap(details.historyElt, details.response, swapSpec, {
|
|
3307
|
+
contextElement: details.historyElt,
|
|
3308
|
+
historyRequest: true
|
|
3309
|
+
})
|
|
3310
|
+
setCurrentPathForHistory(details.path)
|
|
3311
|
+
triggerEvent(getDocument().body, 'htmx:historyRestore', { path, cacheMiss: true, serverResponse: details.response })
|
|
3200
3312
|
} else {
|
|
3201
3313
|
triggerErrorEvent(getDocument().body, 'htmx:historyCacheMissLoadError', details)
|
|
3202
3314
|
}
|
|
3203
3315
|
}
|
|
3204
|
-
|
|
3316
|
+
if (triggerEvent(getDocument().body, 'htmx:historyCacheMiss', details)) {
|
|
3317
|
+
request.send() // only send request if event not prevented
|
|
3318
|
+
}
|
|
3205
3319
|
}
|
|
3206
3320
|
|
|
3207
3321
|
/**
|
|
@@ -3212,24 +3326,21 @@ var htmx = (function() {
|
|
|
3212
3326
|
path = path || location.pathname + location.search
|
|
3213
3327
|
const cached = getCachedHistory(path)
|
|
3214
3328
|
if (cached) {
|
|
3215
|
-
const
|
|
3216
|
-
const
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
}, 0) // next 'tick', so browser has time to render layout
|
|
3226
|
-
currentPathForHistory = path
|
|
3227
|
-
triggerEvent(getDocument().body, 'htmx:historyRestore', { path, item: cached })
|
|
3329
|
+
const swapSpec = { swapStyle: 'innerHTML', swapDelay: 0, settleDelay: 0, scroll: cached.scroll }
|
|
3330
|
+
const details = { path, item: cached, historyElt: getHistoryElement(), swapSpec }
|
|
3331
|
+
if (triggerEvent(getDocument().body, 'htmx:historyCacheHit', details)) {
|
|
3332
|
+
swap(details.historyElt, cached.content, swapSpec, {
|
|
3333
|
+
contextElement: details.historyElt,
|
|
3334
|
+
title: cached.title
|
|
3335
|
+
})
|
|
3336
|
+
setCurrentPathForHistory(details.path)
|
|
3337
|
+
triggerEvent(getDocument().body, 'htmx:historyRestore', details)
|
|
3338
|
+
}
|
|
3228
3339
|
} else {
|
|
3229
3340
|
if (htmx.config.refreshOnHistoryMiss) {
|
|
3230
3341
|
// @ts-ignore: optional parameter in reload() function throws error
|
|
3231
3342
|
// noinspection JSUnresolvedReference
|
|
3232
|
-
|
|
3343
|
+
htmx.location.reload(true)
|
|
3233
3344
|
} else {
|
|
3234
3345
|
loadHistoryFromServer(path)
|
|
3235
3346
|
}
|
|
@@ -3334,7 +3445,8 @@ var htmx = (function() {
|
|
|
3334
3445
|
return true
|
|
3335
3446
|
}
|
|
3336
3447
|
|
|
3337
|
-
/**
|
|
3448
|
+
/**
|
|
3449
|
+
* @param {string} name
|
|
3338
3450
|
* @param {string|Array|FormDataEntryValue} value
|
|
3339
3451
|
* @param {FormData} formData */
|
|
3340
3452
|
function addValueToFormData(name, value, formData) {
|
|
@@ -3347,7 +3459,8 @@ var htmx = (function() {
|
|
|
3347
3459
|
}
|
|
3348
3460
|
}
|
|
3349
3461
|
|
|
3350
|
-
/**
|
|
3462
|
+
/**
|
|
3463
|
+
* @param {string} name
|
|
3351
3464
|
* @param {string|Array} value
|
|
3352
3465
|
* @param {FormData} formData */
|
|
3353
3466
|
function removeValueFromFormData(name, value, formData) {
|
|
@@ -3363,6 +3476,22 @@ var htmx = (function() {
|
|
|
3363
3476
|
}
|
|
3364
3477
|
}
|
|
3365
3478
|
|
|
3479
|
+
/**
|
|
3480
|
+
* @param {Element} elt
|
|
3481
|
+
* @returns {string|Array}
|
|
3482
|
+
*/
|
|
3483
|
+
function getValueFromInput(elt) {
|
|
3484
|
+
if (elt instanceof HTMLSelectElement && elt.multiple) {
|
|
3485
|
+
return toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value })
|
|
3486
|
+
}
|
|
3487
|
+
// include file inputs
|
|
3488
|
+
if (elt instanceof HTMLInputElement && elt.files) {
|
|
3489
|
+
return toArray(elt.files)
|
|
3490
|
+
}
|
|
3491
|
+
// @ts-ignore value will be undefined for non-input elements, which is fine
|
|
3492
|
+
return elt.value
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3366
3495
|
/**
|
|
3367
3496
|
* @param {Element[]} processed
|
|
3368
3497
|
* @param {FormData} formData
|
|
@@ -3378,16 +3507,7 @@ var htmx = (function() {
|
|
|
3378
3507
|
}
|
|
3379
3508
|
if (shouldInclude(elt)) {
|
|
3380
3509
|
const name = getRawAttribute(elt, 'name')
|
|
3381
|
-
|
|
3382
|
-
let value = elt.value
|
|
3383
|
-
if (elt instanceof HTMLSelectElement && elt.multiple) {
|
|
3384
|
-
value = toArray(elt.querySelectorAll('option:checked')).map(function(e) { return (/** @type HTMLOptionElement */(e)).value })
|
|
3385
|
-
}
|
|
3386
|
-
// include file inputs
|
|
3387
|
-
if (elt instanceof HTMLInputElement && elt.files) {
|
|
3388
|
-
value = toArray(elt.files)
|
|
3389
|
-
}
|
|
3390
|
-
addValueToFormData(name, value, formData)
|
|
3510
|
+
addValueToFormData(name, getValueFromInput(elt), formData)
|
|
3391
3511
|
if (validate) {
|
|
3392
3512
|
validateElement(elt, errors)
|
|
3393
3513
|
}
|
|
@@ -3398,7 +3518,7 @@ var htmx = (function() {
|
|
|
3398
3518
|
// The input has already been processed and added to the values, but the FormData that will be
|
|
3399
3519
|
// constructed right after on the form, will include it once again. So remove that input's value
|
|
3400
3520
|
// now to avoid duplicates
|
|
3401
|
-
removeValueFromFormData(input.name, input
|
|
3521
|
+
removeValueFromFormData(input.name, getValueFromInput(input), formData)
|
|
3402
3522
|
} else {
|
|
3403
3523
|
processed.push(input)
|
|
3404
3524
|
}
|
|
@@ -3416,7 +3536,6 @@ var htmx = (function() {
|
|
|
3416
3536
|
}
|
|
3417
3537
|
|
|
3418
3538
|
/**
|
|
3419
|
-
*
|
|
3420
3539
|
* @param {Element} elt
|
|
3421
3540
|
* @param {HtmxElementValidationError[]} errors
|
|
3422
3541
|
*/
|
|
@@ -3471,9 +3590,9 @@ var htmx = (function() {
|
|
|
3471
3590
|
validate = validate && internalData.lastButtonClicked.formNoValidate !== true
|
|
3472
3591
|
}
|
|
3473
3592
|
|
|
3474
|
-
// for a non-GET include the
|
|
3593
|
+
// for a non-GET include the related form, which may or may not be a parent element of elt
|
|
3475
3594
|
if (verb !== 'get') {
|
|
3476
|
-
processInputValue(processed, priorityFormData, errors,
|
|
3595
|
+
processInputValue(processed, priorityFormData, errors, getRelatedForm(elt), validate)
|
|
3477
3596
|
}
|
|
3478
3597
|
|
|
3479
3598
|
// include the element itself
|
|
@@ -3553,7 +3672,7 @@ var htmx = (function() {
|
|
|
3553
3672
|
'HX-Trigger': getRawAttribute(elt, 'id'),
|
|
3554
3673
|
'HX-Trigger-Name': getRawAttribute(elt, 'name'),
|
|
3555
3674
|
'HX-Target': getAttributeValue(target, 'id'),
|
|
3556
|
-
'HX-Current-URL':
|
|
3675
|
+
'HX-Current-URL': location.href
|
|
3557
3676
|
}
|
|
3558
3677
|
getValuesForElement(elt, 'hx-headers', false, headers)
|
|
3559
3678
|
if (prompt !== undefined) {
|
|
@@ -3581,7 +3700,7 @@ var htmx = (function() {
|
|
|
3581
3700
|
} else if (paramsValue === '*') {
|
|
3582
3701
|
return inputValues
|
|
3583
3702
|
} else if (paramsValue.indexOf('not ') === 0) {
|
|
3584
|
-
forEach(paramsValue.
|
|
3703
|
+
forEach(paramsValue.slice(4).split(','), function(name) {
|
|
3585
3704
|
name = name.trim()
|
|
3586
3705
|
inputValues.delete(name)
|
|
3587
3706
|
})
|
|
@@ -3631,15 +3750,15 @@ var htmx = (function() {
|
|
|
3631
3750
|
for (let i = 0; i < split.length; i++) {
|
|
3632
3751
|
const value = split[i]
|
|
3633
3752
|
if (value.indexOf('swap:') === 0) {
|
|
3634
|
-
swapSpec.swapDelay = parseInterval(value.
|
|
3753
|
+
swapSpec.swapDelay = parseInterval(value.slice(5))
|
|
3635
3754
|
} else if (value.indexOf('settle:') === 0) {
|
|
3636
|
-
swapSpec.settleDelay = parseInterval(value.
|
|
3755
|
+
swapSpec.settleDelay = parseInterval(value.slice(7))
|
|
3637
3756
|
} else if (value.indexOf('transition:') === 0) {
|
|
3638
|
-
swapSpec.transition = value.
|
|
3757
|
+
swapSpec.transition = value.slice(11) === 'true'
|
|
3639
3758
|
} else if (value.indexOf('ignoreTitle:') === 0) {
|
|
3640
|
-
swapSpec.ignoreTitle = value.
|
|
3759
|
+
swapSpec.ignoreTitle = value.slice(12) === 'true'
|
|
3641
3760
|
} else if (value.indexOf('scroll:') === 0) {
|
|
3642
|
-
const scrollSpec = value.
|
|
3761
|
+
const scrollSpec = value.slice(7)
|
|
3643
3762
|
var splitSpec = scrollSpec.split(':')
|
|
3644
3763
|
const scrollVal = splitSpec.pop()
|
|
3645
3764
|
var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null
|
|
@@ -3647,14 +3766,14 @@ var htmx = (function() {
|
|
|
3647
3766
|
swapSpec.scroll = scrollVal
|
|
3648
3767
|
swapSpec.scrollTarget = selectorVal
|
|
3649
3768
|
} else if (value.indexOf('show:') === 0) {
|
|
3650
|
-
const showSpec = value.
|
|
3769
|
+
const showSpec = value.slice(5)
|
|
3651
3770
|
var splitSpec = showSpec.split(':')
|
|
3652
3771
|
const showVal = splitSpec.pop()
|
|
3653
3772
|
var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null
|
|
3654
3773
|
swapSpec.show = showVal
|
|
3655
3774
|
swapSpec.showTarget = selectorVal
|
|
3656
3775
|
} else if (value.indexOf('focus-scroll:') === 0) {
|
|
3657
|
-
const focusScrollVal = value.
|
|
3776
|
+
const focusScrollVal = value.slice('focus-scroll:'.length)
|
|
3658
3777
|
swapSpec.focusScroll = focusScrollVal == 'true'
|
|
3659
3778
|
} else if (i == 0) {
|
|
3660
3779
|
swapSpec.swapStyle = value
|
|
@@ -3731,6 +3850,11 @@ var htmx = (function() {
|
|
|
3731
3850
|
target = target || last
|
|
3732
3851
|
target.scrollTop = target.scrollHeight
|
|
3733
3852
|
}
|
|
3853
|
+
if (typeof swapSpec.scroll === 'number') {
|
|
3854
|
+
getWindow().setTimeout(function() {
|
|
3855
|
+
window.scrollTo(0, /** @type number */ (swapSpec.scroll))
|
|
3856
|
+
}, 0) // next 'tick', so browser has time to render layout
|
|
3857
|
+
}
|
|
3734
3858
|
}
|
|
3735
3859
|
if (swapSpec.show) {
|
|
3736
3860
|
var target = null
|
|
@@ -3759,9 +3883,10 @@ var htmx = (function() {
|
|
|
3759
3883
|
* @param {string} attr
|
|
3760
3884
|
* @param {boolean=} evalAsDefault
|
|
3761
3885
|
* @param {Object=} values
|
|
3886
|
+
* @param {Event=} event
|
|
3762
3887
|
* @returns {Object}
|
|
3763
3888
|
*/
|
|
3764
|
-
function getValuesForElement(elt, attr, evalAsDefault, values) {
|
|
3889
|
+
function getValuesForElement(elt, attr, evalAsDefault, values, event) {
|
|
3765
3890
|
if (values == null) {
|
|
3766
3891
|
values = {}
|
|
3767
3892
|
}
|
|
@@ -3776,10 +3901,10 @@ var htmx = (function() {
|
|
|
3776
3901
|
return null
|
|
3777
3902
|
}
|
|
3778
3903
|
if (str.indexOf('javascript:') === 0) {
|
|
3779
|
-
str = str.
|
|
3904
|
+
str = str.slice(11)
|
|
3780
3905
|
evaluateValue = true
|
|
3781
3906
|
} else if (str.indexOf('js:') === 0) {
|
|
3782
|
-
str = str.
|
|
3907
|
+
str = str.slice(3)
|
|
3783
3908
|
evaluateValue = true
|
|
3784
3909
|
}
|
|
3785
3910
|
if (str.indexOf('{') !== 0) {
|
|
@@ -3787,7 +3912,13 @@ var htmx = (function() {
|
|
|
3787
3912
|
}
|
|
3788
3913
|
let varsValues
|
|
3789
3914
|
if (evaluateValue) {
|
|
3790
|
-
varsValues = maybeEval(elt, function() {
|
|
3915
|
+
varsValues = maybeEval(elt, function() {
|
|
3916
|
+
if (event) {
|
|
3917
|
+
return Function('event', 'return (' + str + ')').call(elt, event)
|
|
3918
|
+
} else { // allow window.event to be accessible
|
|
3919
|
+
return Function('return (' + str + ')').call(elt)
|
|
3920
|
+
}
|
|
3921
|
+
}, {})
|
|
3791
3922
|
} else {
|
|
3792
3923
|
varsValues = parseJSON(str)
|
|
3793
3924
|
}
|
|
@@ -3799,7 +3930,7 @@ var htmx = (function() {
|
|
|
3799
3930
|
}
|
|
3800
3931
|
}
|
|
3801
3932
|
}
|
|
3802
|
-
return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values)
|
|
3933
|
+
return getValuesForElement(asElement(parentElt(elt)), attr, evalAsDefault, values, event)
|
|
3803
3934
|
}
|
|
3804
3935
|
|
|
3805
3936
|
/**
|
|
@@ -3819,28 +3950,31 @@ var htmx = (function() {
|
|
|
3819
3950
|
|
|
3820
3951
|
/**
|
|
3821
3952
|
* @param {Element} elt
|
|
3822
|
-
* @param {
|
|
3953
|
+
* @param {Event=} event
|
|
3954
|
+
* @param {*?=} expressionVars
|
|
3823
3955
|
* @returns
|
|
3824
3956
|
*/
|
|
3825
|
-
function getHXVarsForElement(elt, expressionVars) {
|
|
3826
|
-
return getValuesForElement(elt, 'hx-vars', true, expressionVars)
|
|
3957
|
+
function getHXVarsForElement(elt, event, expressionVars) {
|
|
3958
|
+
return getValuesForElement(elt, 'hx-vars', true, expressionVars, event)
|
|
3827
3959
|
}
|
|
3828
3960
|
|
|
3829
3961
|
/**
|
|
3830
3962
|
* @param {Element} elt
|
|
3831
|
-
* @param {
|
|
3963
|
+
* @param {Event=} event
|
|
3964
|
+
* @param {*?=} expressionVars
|
|
3832
3965
|
* @returns
|
|
3833
3966
|
*/
|
|
3834
|
-
function getHXValsForElement(elt, expressionVars) {
|
|
3835
|
-
return getValuesForElement(elt, 'hx-vals', false, expressionVars)
|
|
3967
|
+
function getHXValsForElement(elt, event, expressionVars) {
|
|
3968
|
+
return getValuesForElement(elt, 'hx-vals', false, expressionVars, event)
|
|
3836
3969
|
}
|
|
3837
3970
|
|
|
3838
3971
|
/**
|
|
3839
3972
|
* @param {Element} elt
|
|
3973
|
+
* @param {Event=} event
|
|
3840
3974
|
* @returns {FormData}
|
|
3841
3975
|
*/
|
|
3842
|
-
function getExpressionVars(elt) {
|
|
3843
|
-
return mergeObjects(getHXVarsForElement(elt), getHXValsForElement(elt))
|
|
3976
|
+
function getExpressionVars(elt, event) {
|
|
3977
|
+
return mergeObjects(getHXVarsForElement(elt, event), getHXValsForElement(elt, event))
|
|
3844
3978
|
}
|
|
3845
3979
|
|
|
3846
3980
|
/**
|
|
@@ -3865,8 +3999,7 @@ var htmx = (function() {
|
|
|
3865
3999
|
* @return {string}
|
|
3866
4000
|
*/
|
|
3867
4001
|
function getPathFromResponse(xhr) {
|
|
3868
|
-
|
|
3869
|
-
if (xhr.responseURL && typeof (URL) !== 'undefined') {
|
|
4002
|
+
if (xhr.responseURL) {
|
|
3870
4003
|
try {
|
|
3871
4004
|
const url = new URL(xhr.responseURL)
|
|
3872
4005
|
return url.pathname + url.search
|
|
@@ -3905,9 +4038,9 @@ var htmx = (function() {
|
|
|
3905
4038
|
})
|
|
3906
4039
|
} else {
|
|
3907
4040
|
let resolvedTarget = resolveTarget(context.target)
|
|
3908
|
-
// If target is supplied but can't resolve OR both target and source can't be resolved
|
|
4041
|
+
// If target is supplied but can't resolve OR source is supplied but both target and source can't be resolved
|
|
3909
4042
|
// then use DUMMY_ELT to abort the request with htmx:targetError to avoid it replacing body by mistake
|
|
3910
|
-
if ((context.target && !resolvedTarget) || (!resolvedTarget && !resolveTarget(context.source))) {
|
|
4043
|
+
if ((context.target && !resolvedTarget) || (context.source && !resolvedTarget && !resolveTarget(context.source))) {
|
|
3911
4044
|
resolvedTarget = DUMMY_ELT
|
|
3912
4045
|
}
|
|
3913
4046
|
return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event,
|
|
@@ -3948,17 +4081,9 @@ var htmx = (function() {
|
|
|
3948
4081
|
* @return {boolean}
|
|
3949
4082
|
*/
|
|
3950
4083
|
function verifyPath(elt, path, requestConfig) {
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
url = new URL(path, document.location.href)
|
|
3955
|
-
const origin = document.location.origin
|
|
3956
|
-
sameHost = origin === url.origin
|
|
3957
|
-
} else {
|
|
3958
|
-
// IE11 doesn't support URL
|
|
3959
|
-
url = path
|
|
3960
|
-
sameHost = startsWith(path, document.location.origin)
|
|
3961
|
-
}
|
|
4084
|
+
const url = new URL(path, location.protocol !== 'about:' ? location.href : window.origin)
|
|
4085
|
+
const origin = location.protocol !== 'about:' ? location.origin : window.origin
|
|
4086
|
+
const sameHost = origin === url.origin
|
|
3962
4087
|
|
|
3963
4088
|
if (htmx.config.selfRequestsOnly) {
|
|
3964
4089
|
if (!sameHost) {
|
|
@@ -4039,7 +4164,15 @@ var htmx = (function() {
|
|
|
4039
4164
|
get: function(target, name) {
|
|
4040
4165
|
if (typeof name === 'symbol') {
|
|
4041
4166
|
// Forward symbol calls to the FormData itself directly
|
|
4042
|
-
|
|
4167
|
+
const result = Reflect.get(target, name)
|
|
4168
|
+
// Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error
|
|
4169
|
+
if (typeof result === 'function') {
|
|
4170
|
+
return function() {
|
|
4171
|
+
return result.apply(formData, arguments)
|
|
4172
|
+
}
|
|
4173
|
+
} else {
|
|
4174
|
+
return result
|
|
4175
|
+
}
|
|
4043
4176
|
}
|
|
4044
4177
|
if (name === 'toJSON') {
|
|
4045
4178
|
// Support JSON.stringify call on proxy
|
|
@@ -4051,8 +4184,6 @@ var htmx = (function() {
|
|
|
4051
4184
|
return function() {
|
|
4052
4185
|
return formData[name].apply(formData, arguments)
|
|
4053
4186
|
}
|
|
4054
|
-
} else {
|
|
4055
|
-
return target[name]
|
|
4056
4187
|
}
|
|
4057
4188
|
}
|
|
4058
4189
|
const array = formData.getAll(name)
|
|
@@ -4127,7 +4258,7 @@ var htmx = (function() {
|
|
|
4127
4258
|
}
|
|
4128
4259
|
const target = etc.targetOverride || asElement(getTarget(elt))
|
|
4129
4260
|
if (target == null || target == DUMMY_ELT) {
|
|
4130
|
-
triggerErrorEvent(elt, 'htmx:targetError', { target:
|
|
4261
|
+
triggerErrorEvent(elt, 'htmx:targetError', { target: getClosestAttributeValue(elt, 'hx-target') })
|
|
4131
4262
|
maybeCall(reject)
|
|
4132
4263
|
return promise
|
|
4133
4264
|
}
|
|
@@ -4143,9 +4274,11 @@ var htmx = (function() {
|
|
|
4143
4274
|
|
|
4144
4275
|
const buttonVerb = getRawAttribute(submitter, 'formmethod')
|
|
4145
4276
|
if (buttonVerb != null) {
|
|
4146
|
-
|
|
4147
|
-
if (buttonVerb.toLowerCase() !== 'dialog') {
|
|
4277
|
+
if (VERBS.includes(buttonVerb.toLowerCase())) {
|
|
4148
4278
|
verb = (/** @type HttpVerb */(buttonVerb))
|
|
4279
|
+
} else {
|
|
4280
|
+
maybeCall(resolve)
|
|
4281
|
+
return promise
|
|
4149
4282
|
}
|
|
4150
4283
|
}
|
|
4151
4284
|
}
|
|
@@ -4280,7 +4413,7 @@ var htmx = (function() {
|
|
|
4280
4413
|
if (etc.values) {
|
|
4281
4414
|
overrideFormData(rawFormData, formDataFromObject(etc.values))
|
|
4282
4415
|
}
|
|
4283
|
-
const expressionVars = formDataFromObject(getExpressionVars(elt))
|
|
4416
|
+
const expressionVars = formDataFromObject(getExpressionVars(elt, event))
|
|
4284
4417
|
const allFormData = overrideFormData(rawFormData, expressionVars)
|
|
4285
4418
|
let filteredFormData = filterValues(allFormData, elt)
|
|
4286
4419
|
|
|
@@ -4290,7 +4423,7 @@ var htmx = (function() {
|
|
|
4290
4423
|
|
|
4291
4424
|
// behavior of anchors w/ empty href is to use the current URL
|
|
4292
4425
|
if (path == null || path === '') {
|
|
4293
|
-
path =
|
|
4426
|
+
path = location.href
|
|
4294
4427
|
}
|
|
4295
4428
|
|
|
4296
4429
|
/**
|
|
@@ -4314,6 +4447,7 @@ var htmx = (function() {
|
|
|
4314
4447
|
unfilteredFormData: allFormData,
|
|
4315
4448
|
unfilteredParameters: formDataProxy(allFormData),
|
|
4316
4449
|
headers,
|
|
4450
|
+
elt,
|
|
4317
4451
|
target,
|
|
4318
4452
|
verb,
|
|
4319
4453
|
errors,
|
|
@@ -4368,6 +4502,7 @@ var htmx = (function() {
|
|
|
4368
4502
|
if (!verifyPath(elt, finalPath, requestConfig)) {
|
|
4369
4503
|
triggerErrorEvent(elt, 'htmx:invalidPath', requestConfig)
|
|
4370
4504
|
maybeCall(reject)
|
|
4505
|
+
endRequestLock()
|
|
4371
4506
|
return promise
|
|
4372
4507
|
}
|
|
4373
4508
|
|
|
@@ -4430,10 +4565,11 @@ var htmx = (function() {
|
|
|
4430
4565
|
}
|
|
4431
4566
|
}
|
|
4432
4567
|
maybeCall(resolve)
|
|
4433
|
-
endRequestLock()
|
|
4434
4568
|
} catch (e) {
|
|
4435
4569
|
triggerErrorEvent(elt, 'htmx:onLoadError', mergeObjects({ error: e }, responseInfo))
|
|
4436
4570
|
throw e
|
|
4571
|
+
} finally {
|
|
4572
|
+
endRequestLock()
|
|
4437
4573
|
}
|
|
4438
4574
|
}
|
|
4439
4575
|
xhr.onerror = function() {
|
|
@@ -4608,13 +4744,31 @@ var htmx = (function() {
|
|
|
4608
4744
|
if (title) {
|
|
4609
4745
|
const titleElt = find('title')
|
|
4610
4746
|
if (titleElt) {
|
|
4611
|
-
titleElt.
|
|
4747
|
+
titleElt.textContent = title
|
|
4612
4748
|
} else {
|
|
4613
4749
|
window.document.title = title
|
|
4614
4750
|
}
|
|
4615
4751
|
}
|
|
4616
4752
|
}
|
|
4617
4753
|
|
|
4754
|
+
/**
|
|
4755
|
+
* Resove the Retarget selector and throw if not found
|
|
4756
|
+
* @param {Element} elt
|
|
4757
|
+
* @param {String} target
|
|
4758
|
+
* @returns {Element}
|
|
4759
|
+
*/
|
|
4760
|
+
function resolveRetarget(elt, target) {
|
|
4761
|
+
if (target === 'this') {
|
|
4762
|
+
return elt
|
|
4763
|
+
}
|
|
4764
|
+
const resolvedTarget = asElement(querySelectorExt(elt, target))
|
|
4765
|
+
if (resolvedTarget == null) {
|
|
4766
|
+
triggerErrorEvent(elt, 'htmx:targetError', { target })
|
|
4767
|
+
throw new Error(`Invalid re-target ${target}`)
|
|
4768
|
+
}
|
|
4769
|
+
return resolvedTarget
|
|
4770
|
+
}
|
|
4771
|
+
|
|
4618
4772
|
/**
|
|
4619
4773
|
* @param {Element} elt
|
|
4620
4774
|
* @param {HtmxResponseInfo} responseInfo
|
|
@@ -4652,25 +4806,17 @@ var htmx = (function() {
|
|
|
4652
4806
|
|
|
4653
4807
|
if (hasHeader(xhr, /HX-Redirect:/i)) {
|
|
4654
4808
|
responseInfo.keepIndicators = true
|
|
4655
|
-
location.href = xhr.getResponseHeader('HX-Redirect')
|
|
4656
|
-
shouldRefresh && location.reload()
|
|
4809
|
+
htmx.location.href = xhr.getResponseHeader('HX-Redirect')
|
|
4810
|
+
shouldRefresh && htmx.location.reload()
|
|
4657
4811
|
return
|
|
4658
4812
|
}
|
|
4659
4813
|
|
|
4660
4814
|
if (shouldRefresh) {
|
|
4661
4815
|
responseInfo.keepIndicators = true
|
|
4662
|
-
location.reload()
|
|
4816
|
+
htmx.location.reload()
|
|
4663
4817
|
return
|
|
4664
4818
|
}
|
|
4665
4819
|
|
|
4666
|
-
if (hasHeader(xhr, /HX-Retarget:/i)) {
|
|
4667
|
-
if (xhr.getResponseHeader('HX-Retarget') === 'this') {
|
|
4668
|
-
responseInfo.target = elt
|
|
4669
|
-
} else {
|
|
4670
|
-
responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget')))
|
|
4671
|
-
}
|
|
4672
|
-
}
|
|
4673
|
-
|
|
4674
4820
|
const historyUpdate = determineHistoryUpdates(elt, responseInfo)
|
|
4675
4821
|
|
|
4676
4822
|
const responseHandling = resolveResponseHandling(xhr)
|
|
@@ -4679,7 +4825,7 @@ var htmx = (function() {
|
|
|
4679
4825
|
let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle
|
|
4680
4826
|
let selectOverride = responseHandling.select
|
|
4681
4827
|
if (responseHandling.target) {
|
|
4682
|
-
responseInfo.target =
|
|
4828
|
+
responseInfo.target = resolveRetarget(elt, responseHandling.target)
|
|
4683
4829
|
}
|
|
4684
4830
|
var swapOverride = etc.swapOverride
|
|
4685
4831
|
if (swapOverride == null && responseHandling.swapOverride) {
|
|
@@ -4688,12 +4834,9 @@ var htmx = (function() {
|
|
|
4688
4834
|
|
|
4689
4835
|
// response headers override response handling config
|
|
4690
4836
|
if (hasHeader(xhr, /HX-Retarget:/i)) {
|
|
4691
|
-
|
|
4692
|
-
responseInfo.target = elt
|
|
4693
|
-
} else {
|
|
4694
|
-
responseInfo.target = asElement(querySelectorExt(elt, xhr.getResponseHeader('HX-Retarget')))
|
|
4695
|
-
}
|
|
4837
|
+
responseInfo.target = resolveRetarget(elt, xhr.getResponseHeader('HX-Retarget'))
|
|
4696
4838
|
}
|
|
4839
|
+
|
|
4697
4840
|
if (hasHeader(xhr, /HX-Reswap:/i)) {
|
|
4698
4841
|
swapOverride = xhr.getResponseHeader('HX-Reswap')
|
|
4699
4842
|
}
|
|
@@ -4746,10 +4889,6 @@ var htmx = (function() {
|
|
|
4746
4889
|
|
|
4747
4890
|
target.classList.add(htmx.config.swappingClass)
|
|
4748
4891
|
|
|
4749
|
-
// optional transition API promise callbacks
|
|
4750
|
-
let settleResolve = null
|
|
4751
|
-
let settleReject = null
|
|
4752
|
-
|
|
4753
4892
|
if (responseInfoSelect) {
|
|
4754
4893
|
selectOverride = responseInfoSelect
|
|
4755
4894
|
}
|
|
@@ -4761,8 +4900,31 @@ var htmx = (function() {
|
|
|
4761
4900
|
const selectOOB = getClosestAttributeValue(elt, 'hx-select-oob')
|
|
4762
4901
|
const select = getClosestAttributeValue(elt, 'hx-select')
|
|
4763
4902
|
|
|
4764
|
-
|
|
4765
|
-
|
|
4903
|
+
swap(target, serverResponse, swapSpec, {
|
|
4904
|
+
select: selectOverride === 'unset' ? null : selectOverride || select,
|
|
4905
|
+
selectOOB,
|
|
4906
|
+
eventInfo: responseInfo,
|
|
4907
|
+
anchor: responseInfo.pathInfo.anchor,
|
|
4908
|
+
contextElement: elt,
|
|
4909
|
+
afterSwapCallback: function() {
|
|
4910
|
+
if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) {
|
|
4911
|
+
let finalElt = elt
|
|
4912
|
+
if (!bodyContains(elt)) {
|
|
4913
|
+
finalElt = getDocument().body
|
|
4914
|
+
}
|
|
4915
|
+
handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt)
|
|
4916
|
+
}
|
|
4917
|
+
},
|
|
4918
|
+
afterSettleCallback: function() {
|
|
4919
|
+
if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) {
|
|
4920
|
+
let finalElt = elt
|
|
4921
|
+
if (!bodyContains(elt)) {
|
|
4922
|
+
finalElt = getDocument().body
|
|
4923
|
+
}
|
|
4924
|
+
handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt)
|
|
4925
|
+
}
|
|
4926
|
+
},
|
|
4927
|
+
beforeSwapCallback: function() {
|
|
4766
4928
|
// if we need to save history, do so, before swapping so that relative resources have the correct base URL
|
|
4767
4929
|
if (historyUpdate.type) {
|
|
4768
4930
|
triggerEvent(getDocument().body, 'htmx:beforeHistoryUpdate', mergeObjects({ history: historyUpdate }, responseInfo))
|
|
@@ -4774,70 +4936,8 @@ var htmx = (function() {
|
|
|
4774
4936
|
triggerEvent(getDocument().body, 'htmx:replacedInHistory', { path: historyUpdate.path })
|
|
4775
4937
|
}
|
|
4776
4938
|
}
|
|
4777
|
-
|
|
4778
|
-
swap(target, serverResponse, swapSpec, {
|
|
4779
|
-
select: selectOverride || select,
|
|
4780
|
-
selectOOB,
|
|
4781
|
-
eventInfo: responseInfo,
|
|
4782
|
-
anchor: responseInfo.pathInfo.anchor,
|
|
4783
|
-
contextElement: elt,
|
|
4784
|
-
afterSwapCallback: function() {
|
|
4785
|
-
if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) {
|
|
4786
|
-
let finalElt = elt
|
|
4787
|
-
if (!bodyContains(elt)) {
|
|
4788
|
-
finalElt = getDocument().body
|
|
4789
|
-
}
|
|
4790
|
-
handleTriggerHeader(xhr, 'HX-Trigger-After-Swap', finalElt)
|
|
4791
|
-
}
|
|
4792
|
-
},
|
|
4793
|
-
afterSettleCallback: function() {
|
|
4794
|
-
if (hasHeader(xhr, /HX-Trigger-After-Settle:/i)) {
|
|
4795
|
-
let finalElt = elt
|
|
4796
|
-
if (!bodyContains(elt)) {
|
|
4797
|
-
finalElt = getDocument().body
|
|
4798
|
-
}
|
|
4799
|
-
handleTriggerHeader(xhr, 'HX-Trigger-After-Settle', finalElt)
|
|
4800
|
-
}
|
|
4801
|
-
maybeCall(settleResolve)
|
|
4802
|
-
}
|
|
4803
|
-
})
|
|
4804
|
-
} catch (e) {
|
|
4805
|
-
triggerErrorEvent(elt, 'htmx:swapError', responseInfo)
|
|
4806
|
-
maybeCall(settleReject)
|
|
4807
|
-
throw e
|
|
4808
4939
|
}
|
|
4809
|
-
}
|
|
4810
|
-
|
|
4811
|
-
let shouldTransition = htmx.config.globalViewTransitions
|
|
4812
|
-
if (swapSpec.hasOwnProperty('transition')) {
|
|
4813
|
-
shouldTransition = swapSpec.transition
|
|
4814
|
-
}
|
|
4815
|
-
|
|
4816
|
-
if (shouldTransition &&
|
|
4817
|
-
triggerEvent(elt, 'htmx:beforeTransition', responseInfo) &&
|
|
4818
|
-
typeof Promise !== 'undefined' &&
|
|
4819
|
-
// @ts-ignore experimental feature atm
|
|
4820
|
-
document.startViewTransition) {
|
|
4821
|
-
const settlePromise = new Promise(function(_resolve, _reject) {
|
|
4822
|
-
settleResolve = _resolve
|
|
4823
|
-
settleReject = _reject
|
|
4824
|
-
})
|
|
4825
|
-
// wrap the original doSwap() in a call to startViewTransition()
|
|
4826
|
-
const innerDoSwap = doSwap
|
|
4827
|
-
doSwap = function() {
|
|
4828
|
-
// @ts-ignore experimental feature atm
|
|
4829
|
-
document.startViewTransition(function() {
|
|
4830
|
-
innerDoSwap()
|
|
4831
|
-
return settlePromise
|
|
4832
|
-
})
|
|
4833
|
-
}
|
|
4834
|
-
}
|
|
4835
|
-
|
|
4836
|
-
if (swapSpec.swapDelay > 0) {
|
|
4837
|
-
getWindow().setTimeout(doSwap, swapSpec.swapDelay)
|
|
4838
|
-
} else {
|
|
4839
|
-
doSwap()
|
|
4840
|
-
}
|
|
4940
|
+
})
|
|
4841
4941
|
}
|
|
4842
4942
|
if (isError) {
|
|
4843
4943
|
triggerErrorEvent(elt, 'htmx:responseError', mergeObjects({ error: 'Response Status Error Code ' + xhr.status + ' from ' + responseInfo.pathInfo.requestPath }, responseInfo))
|
|
@@ -4873,7 +4973,7 @@ var htmx = (function() {
|
|
|
4873
4973
|
* @see https://htmx.org/api/#defineExtension
|
|
4874
4974
|
*
|
|
4875
4975
|
* @param {string} name the extension name
|
|
4876
|
-
* @param {HtmxExtension} extension the extension definition
|
|
4976
|
+
* @param {Partial<HtmxExtension>} extension the extension definition
|
|
4877
4977
|
*/
|
|
4878
4978
|
function defineExtension(name, extension) {
|
|
4879
4979
|
if (extension.init) {
|
|
@@ -5038,6 +5138,9 @@ var htmx = (function() {
|
|
|
5038
5138
|
* @property {Element} [contextElement]
|
|
5039
5139
|
* @property {swapCallback} [afterSwapCallback]
|
|
5040
5140
|
* @property {swapCallback} [afterSettleCallback]
|
|
5141
|
+
* @property {swapCallback} [beforeSwapCallback]
|
|
5142
|
+
* @property {string} [title]
|
|
5143
|
+
* @property {boolean} [historyRequest]
|
|
5041
5144
|
*/
|
|
5042
5145
|
|
|
5043
5146
|
/**
|
|
@@ -5056,7 +5159,7 @@ var htmx = (function() {
|
|
|
5056
5159
|
* @property {boolean} [transition]
|
|
5057
5160
|
* @property {boolean} [ignoreTitle]
|
|
5058
5161
|
* @property {string} [head]
|
|
5059
|
-
* @property {'top' | 'bottom'} [scroll]
|
|
5162
|
+
* @property {'top' | 'bottom' | number } [scroll]
|
|
5060
5163
|
* @property {string} [scrollTarget]
|
|
5061
5164
|
* @property {string} [show]
|
|
5062
5165
|
* @property {string} [showTarget]
|
|
@@ -5101,7 +5204,8 @@ var htmx = (function() {
|
|
|
5101
5204
|
* @property {'true'} [HX-History-Restore-Request]
|
|
5102
5205
|
*/
|
|
5103
5206
|
|
|
5104
|
-
/**
|
|
5207
|
+
/**
|
|
5208
|
+
* @typedef HtmxAjaxHelperContext
|
|
5105
5209
|
* @property {Element|string} [source]
|
|
5106
5210
|
* @property {Event} [event]
|
|
5107
5211
|
* @property {HtmxAjaxHandler} [handler]
|
|
@@ -5121,6 +5225,7 @@ var htmx = (function() {
|
|
|
5121
5225
|
* @property {FormData} unfilteredFormData
|
|
5122
5226
|
* @property {Object} unfilteredParameters unfilteredFormData proxy
|
|
5123
5227
|
* @property {HtmxHeaderSpecification} headers
|
|
5228
|
+
* @property {Element} elt
|
|
5124
5229
|
* @property {Element} target
|
|
5125
5230
|
* @property {HttpVerb} verb
|
|
5126
5231
|
* @property {HtmxElementValidationError[]} errors
|
|
@@ -5194,7 +5299,7 @@ var htmx = (function() {
|
|
|
5194
5299
|
* @see https://github.com/bigskysoftware/htmx-extensions/blob/main/README.md
|
|
5195
5300
|
* @typedef {Object} HtmxExtension
|
|
5196
5301
|
* @property {(api: any) => void} init
|
|
5197
|
-
* @property {(name: string, event:
|
|
5302
|
+
* @property {(name: string, event: CustomEvent) => boolean} onEvent
|
|
5198
5303
|
* @property {(text: string, xhr: XMLHttpRequest, elt: Element) => string} transformResponse
|
|
5199
5304
|
* @property {(swapStyle: HtmxSwapStyle) => boolean} isInlineSwap
|
|
5200
5305
|
* @property {(swapStyle: HtmxSwapStyle, target: Node, fragment: Node, settleInfo: HtmxSettleInfo) => boolean|Node[]} handleSwap
|