htmx.org 2.0.3 → 2.0.4

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 CHANGED
@@ -32,7 +32,7 @@ By removing these arbitrary constraints htmx completes HTML as a
32
32
  ## quick start
33
33
 
34
34
  ```html
35
- <script src="https://unpkg.com/htmx.org@2.0.3"></script>
35
+ <script src="https://unpkg.com/htmx.org@2.0.4"></script>
36
36
  <!-- have a button POST a click via AJAX -->
37
37
  <button hx-post="/clicked" hx-swap="outerHTML">
38
38
  Click Me
package/dist/htmx.amd.js CHANGED
@@ -278,7 +278,7 @@ var htmx = (function() {
278
278
  parseInterval: null,
279
279
  /** @type {typeof internalEval} */
280
280
  _: null,
281
- version: '2.0.3'
281
+ version: '2.0.4'
282
282
  }
283
283
  // Tsc madness part 2
284
284
  htmx.onLoad = onLoadHelper
@@ -694,6 +694,7 @@ var htmx = (function() {
694
694
  * @property {XMLHttpRequest} [xhr]
695
695
  * @property {(() => void)[]} [queuedRequests]
696
696
  * @property {boolean} [abortable]
697
+ * @property {boolean} [firstInitCompleted]
697
698
  *
698
699
  * Event data
699
700
  * @property {HtmxTriggerSpecification} [triggerSpec]
@@ -755,17 +756,14 @@ var htmx = (function() {
755
756
  }
756
757
 
757
758
  /**
759
+ * Checks whether the element is in the document (includes shadow roots).
760
+ * This function this is a slight misnomer; it will return true even for elements in the head.
761
+ *
758
762
  * @param {Node} elt
759
763
  * @returns {boolean}
760
764
  */
761
765
  function bodyContains(elt) {
762
- // IE Fix
763
- const rootNode = elt.getRootNode && elt.getRootNode()
764
- if (rootNode && rootNode instanceof window.ShadowRoot) {
765
- return getDocument().body.contains(rootNode.host)
766
- } else {
767
- return getDocument().body.contains(elt)
768
- }
766
+ return elt.getRootNode({ composed: true }) === document
769
767
  }
770
768
 
771
769
  /**
@@ -1129,34 +1127,77 @@ var htmx = (function() {
1129
1127
  * @returns {(Node|Window)[]}
1130
1128
  */
1131
1129
  function querySelectorAllExt(elt, selector, global) {
1132
- elt = resolveTarget(elt)
1133
- if (selector.indexOf('closest ') === 0) {
1134
- return [closest(asElement(elt), normalizeSelector(selector.substr(8)))]
1135
- } else if (selector.indexOf('find ') === 0) {
1136
- return [find(asParentNode(elt), normalizeSelector(selector.substr(5)))]
1137
- } else if (selector === 'next') {
1138
- return [asElement(elt).nextElementSibling]
1139
- } else if (selector.indexOf('next ') === 0) {
1140
- return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)]
1141
- } else if (selector === 'previous') {
1142
- return [asElement(elt).previousElementSibling]
1143
- } else if (selector.indexOf('previous ') === 0) {
1144
- return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)]
1145
- } else if (selector === 'document') {
1146
- return [document]
1147
- } else if (selector === 'window') {
1148
- return [window]
1149
- } else if (selector === 'body') {
1150
- return [document.body]
1151
- } else if (selector === 'root') {
1152
- return [getRootNode(elt, !!global)]
1153
- } else if (selector === 'host') {
1154
- return [(/** @type ShadowRoot */(elt.getRootNode())).host]
1155
- } else if (selector.indexOf('global ') === 0) {
1130
+ if (selector.indexOf('global ') === 0) {
1156
1131
  return querySelectorAllExt(elt, selector.slice(7), true)
1157
- } else {
1158
- return toArray(asParentNode(getRootNode(elt, !!global)).querySelectorAll(normalizeSelector(selector)))
1159
1132
  }
1133
+
1134
+ elt = resolveTarget(elt)
1135
+
1136
+ const parts = []
1137
+ {
1138
+ let chevronsCount = 0
1139
+ let offset = 0
1140
+ for (let i = 0; i < selector.length; i++) {
1141
+ const char = selector[i]
1142
+ if (char === ',' && chevronsCount === 0) {
1143
+ parts.push(selector.substring(offset, i))
1144
+ offset = i + 1
1145
+ continue
1146
+ }
1147
+ if (char === '<') {
1148
+ chevronsCount++
1149
+ } else if (char === '/' && i < selector.length - 1 && selector[i + 1] === '>') {
1150
+ chevronsCount--
1151
+ }
1152
+ }
1153
+ if (offset < selector.length) {
1154
+ parts.push(selector.substring(offset))
1155
+ }
1156
+ }
1157
+
1158
+ const result = []
1159
+ const unprocessedParts = []
1160
+ while (parts.length > 0) {
1161
+ const selector = normalizeSelector(parts.shift())
1162
+ let item
1163
+ if (selector.indexOf('closest ') === 0) {
1164
+ item = closest(asElement(elt), normalizeSelector(selector.substr(8)))
1165
+ } else if (selector.indexOf('find ') === 0) {
1166
+ item = find(asParentNode(elt), normalizeSelector(selector.substr(5)))
1167
+ } else if (selector === 'next' || selector === 'nextElementSibling') {
1168
+ item = asElement(elt).nextElementSibling
1169
+ } else if (selector.indexOf('next ') === 0) {
1170
+ item = scanForwardQuery(elt, normalizeSelector(selector.substr(5)), !!global)
1171
+ } else if (selector === 'previous' || selector === 'previousElementSibling') {
1172
+ item = asElement(elt).previousElementSibling
1173
+ } else if (selector.indexOf('previous ') === 0) {
1174
+ item = scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)), !!global)
1175
+ } else if (selector === 'document') {
1176
+ item = document
1177
+ } else if (selector === 'window') {
1178
+ item = window
1179
+ } else if (selector === 'body') {
1180
+ item = document.body
1181
+ } else if (selector === 'root') {
1182
+ item = getRootNode(elt, !!global)
1183
+ } else if (selector === 'host') {
1184
+ item = (/** @type ShadowRoot */(elt.getRootNode())).host
1185
+ } else {
1186
+ unprocessedParts.push(selector)
1187
+ }
1188
+
1189
+ if (item) {
1190
+ result.push(item)
1191
+ }
1192
+ }
1193
+
1194
+ if (unprocessedParts.length > 0) {
1195
+ const standardSelector = unprocessedParts.join(',')
1196
+ const rootNode = asParentNode(getRootNode(elt, !!global))
1197
+ result.push(...toArray(rootNode.querySelectorAll(standardSelector)))
1198
+ }
1199
+
1200
+ return result
1160
1201
  }
1161
1202
 
1162
1203
  /**
@@ -1419,8 +1460,8 @@ var htmx = (function() {
1419
1460
  if (oobValue === 'true') {
1420
1461
  // do nothing
1421
1462
  } else if (oobValue.indexOf(':') > 0) {
1422
- swapStyle = oobValue.substr(0, oobValue.indexOf(':'))
1423
- selector = oobValue.substr(oobValue.indexOf(':') + 1, oobValue.length)
1463
+ swapStyle = oobValue.substring(0, oobValue.indexOf(':'))
1464
+ selector = oobValue.substring(oobValue.indexOf(':') + 1)
1424
1465
  } else {
1425
1466
  swapStyle = oobValue
1426
1467
  }
@@ -1629,7 +1670,7 @@ var htmx = (function() {
1629
1670
  })
1630
1671
  }
1631
1672
  deInitOnHandlers(element)
1632
- forEach(Object.keys(internalData), function(key) { delete internalData[key] })
1673
+ forEach(Object.keys(internalData), function(key) { if (key !== 'firstInitCompleted') delete internalData[key] })
1633
1674
  }
1634
1675
 
1635
1676
  /**
@@ -1890,7 +1931,7 @@ var htmx = (function() {
1890
1931
  // oob swaps
1891
1932
  findAndSwapOobElements(fragment, settleInfo, rootNode)
1892
1933
  forEach(findAll(fragment, 'template'), /** @param {HTMLTemplateElement} template */function(template) {
1893
- if (findAndSwapOobElements(template.content, settleInfo, rootNode)) {
1934
+ if (template.content && findAndSwapOobElements(template.content, settleInfo, rootNode)) {
1894
1935
  // Avoid polluting the DOM with empty templates that were only used to encapsulate oob swap
1895
1936
  template.remove()
1896
1937
  }
@@ -2029,7 +2070,7 @@ var htmx = (function() {
2029
2070
  while (SYMBOL_CONT.exec(str.charAt(position + 1))) {
2030
2071
  position++
2031
2072
  }
2032
- tokens.push(str.substr(startPosition, position - startPosition + 1))
2073
+ tokens.push(str.substring(startPosition, position + 1))
2033
2074
  } else if (STRINGISH_START.indexOf(str.charAt(position)) !== -1) {
2034
2075
  const startChar = str.charAt(position)
2035
2076
  var startPosition = position
@@ -2040,7 +2081,7 @@ var htmx = (function() {
2040
2081
  }
2041
2082
  position++
2042
2083
  }
2043
- tokens.push(str.substr(startPosition, position - startPosition + 1))
2084
+ tokens.push(str.substring(startPosition, position + 1))
2044
2085
  } else {
2045
2086
  const symbol = str.charAt(position)
2046
2087
  tokens.push(symbol)
@@ -2324,6 +2365,11 @@ var htmx = (function() {
2324
2365
  const rawAttribute = getRawAttribute(elt, 'method')
2325
2366
  verb = (/** @type HttpVerb */(rawAttribute ? rawAttribute.toLowerCase() : 'get'))
2326
2367
  path = getRawAttribute(elt, 'action')
2368
+ if (path == null || path === '') {
2369
+ // if there is no action attribute on the form set path to current href before the
2370
+ // following logic to properly clear parameters on a GET (not on a POST!)
2371
+ path = getDocument().location.href
2372
+ }
2327
2373
  if (verb === 'get' && path.includes('?')) {
2328
2374
  path = path.replace(/\?[^#]+/, '')
2329
2375
  }
@@ -2355,7 +2401,8 @@ var htmx = (function() {
2355
2401
  if (elt.tagName === 'FORM') {
2356
2402
  return true
2357
2403
  }
2358
- if (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) {
2404
+ if (matches(elt, 'input[type="submit"], button') &&
2405
+ (matches(elt, '[form]') || closest(elt, 'form') !== null)) {
2359
2406
  return true
2360
2407
  }
2361
2408
  if (elt instanceof HTMLAnchorElement && elt.href &&
@@ -2560,6 +2607,7 @@ var htmx = (function() {
2560
2607
  const load = function() {
2561
2608
  if (!nodeData.loaded) {
2562
2609
  nodeData.loaded = true
2610
+ triggerEvent(elt, 'htmx:trigger')
2563
2611
  handler(elt)
2564
2612
  }
2565
2613
  }
@@ -2635,7 +2683,7 @@ var htmx = (function() {
2635
2683
  }, observerOptions)
2636
2684
  observer.observe(asElement(elt))
2637
2685
  addEventListener(asElement(elt), handler, nodeData, triggerSpec)
2638
- } else if (triggerSpec.trigger === 'load') {
2686
+ } else if (!nodeData.firstInitCompleted && triggerSpec.trigger === 'load') {
2639
2687
  if (!maybeFilterEvent(triggerSpec, elt, makeEvent('load', { elt }))) {
2640
2688
  loadImmediately(asElement(elt), handler, nodeData, triggerSpec.delay)
2641
2689
  }
@@ -2842,11 +2890,12 @@ var htmx = (function() {
2842
2890
  return
2843
2891
  }
2844
2892
  const nodeData = getInternalData(elt)
2845
- if (nodeData.initHash !== attributeHash(elt)) {
2893
+ const attrHash = attributeHash(elt)
2894
+ if (nodeData.initHash !== attrHash) {
2846
2895
  // clean up any previously processed info
2847
2896
  deInitNode(elt)
2848
2897
 
2849
- nodeData.initHash = attributeHash(elt)
2898
+ nodeData.initHash = attrHash
2850
2899
 
2851
2900
  triggerEvent(elt, 'htmx:beforeProcessNode')
2852
2901
 
@@ -2871,6 +2920,7 @@ var htmx = (function() {
2871
2920
  initButtonTracking(elt)
2872
2921
  }
2873
2922
 
2923
+ nodeData.firstInitCompleted = true
2874
2924
  triggerEvent(elt, 'htmx:afterProcessNode')
2875
2925
  }
2876
2926
  }
@@ -3582,7 +3632,7 @@ var htmx = (function() {
3582
3632
  } else if (paramsValue === '*') {
3583
3633
  return inputValues
3584
3634
  } else if (paramsValue.indexOf('not ') === 0) {
3585
- forEach(paramsValue.substr(4).split(','), function(name) {
3635
+ forEach(paramsValue.slice(4).split(','), function(name) {
3586
3636
  name = name.trim()
3587
3637
  inputValues.delete(name)
3588
3638
  })
@@ -3632,15 +3682,15 @@ var htmx = (function() {
3632
3682
  for (let i = 0; i < split.length; i++) {
3633
3683
  const value = split[i]
3634
3684
  if (value.indexOf('swap:') === 0) {
3635
- swapSpec.swapDelay = parseInterval(value.substr(5))
3685
+ swapSpec.swapDelay = parseInterval(value.slice(5))
3636
3686
  } else if (value.indexOf('settle:') === 0) {
3637
- swapSpec.settleDelay = parseInterval(value.substr(7))
3687
+ swapSpec.settleDelay = parseInterval(value.slice(7))
3638
3688
  } else if (value.indexOf('transition:') === 0) {
3639
- swapSpec.transition = value.substr(11) === 'true'
3689
+ swapSpec.transition = value.slice(11) === 'true'
3640
3690
  } else if (value.indexOf('ignoreTitle:') === 0) {
3641
- swapSpec.ignoreTitle = value.substr(12) === 'true'
3691
+ swapSpec.ignoreTitle = value.slice(12) === 'true'
3642
3692
  } else if (value.indexOf('scroll:') === 0) {
3643
- const scrollSpec = value.substr(7)
3693
+ const scrollSpec = value.slice(7)
3644
3694
  var splitSpec = scrollSpec.split(':')
3645
3695
  const scrollVal = splitSpec.pop()
3646
3696
  var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null
@@ -3648,14 +3698,14 @@ var htmx = (function() {
3648
3698
  swapSpec.scroll = scrollVal
3649
3699
  swapSpec.scrollTarget = selectorVal
3650
3700
  } else if (value.indexOf('show:') === 0) {
3651
- const showSpec = value.substr(5)
3701
+ const showSpec = value.slice(5)
3652
3702
  var splitSpec = showSpec.split(':')
3653
3703
  const showVal = splitSpec.pop()
3654
3704
  var selectorVal = splitSpec.length > 0 ? splitSpec.join(':') : null
3655
3705
  swapSpec.show = showVal
3656
3706
  swapSpec.showTarget = selectorVal
3657
3707
  } else if (value.indexOf('focus-scroll:') === 0) {
3658
- const focusScrollVal = value.substr('focus-scroll:'.length)
3708
+ const focusScrollVal = value.slice('focus-scroll:'.length)
3659
3709
  swapSpec.focusScroll = focusScrollVal == 'true'
3660
3710
  } else if (i == 0) {
3661
3711
  swapSpec.swapStyle = value
@@ -3777,10 +3827,10 @@ var htmx = (function() {
3777
3827
  return null
3778
3828
  }
3779
3829
  if (str.indexOf('javascript:') === 0) {
3780
- str = str.substr(11)
3830
+ str = str.slice(11)
3781
3831
  evaluateValue = true
3782
3832
  } else if (str.indexOf('js:') === 0) {
3783
- str = str.substr(3)
3833
+ str = str.slice(3)
3784
3834
  evaluateValue = true
3785
3835
  }
3786
3836
  if (str.indexOf('{') !== 0) {
@@ -3906,9 +3956,9 @@ var htmx = (function() {
3906
3956
  })
3907
3957
  } else {
3908
3958
  let resolvedTarget = resolveTarget(context.target)
3909
- // If target is supplied but can't resolve OR both target and source can't be resolved
3959
+ // If target is supplied but can't resolve OR source is supplied but both target and source can't be resolved
3910
3960
  // then use DUMMY_ELT to abort the request with htmx:targetError to avoid it replacing body by mistake
3911
- if ((context.target && !resolvedTarget) || (!resolvedTarget && !resolveTarget(context.source))) {
3961
+ if ((context.target && !resolvedTarget) || (context.source && !resolvedTarget && !resolveTarget(context.source))) {
3912
3962
  resolvedTarget = DUMMY_ELT
3913
3963
  }
3914
3964
  return issueAjaxRequest(verb, path, resolveTarget(context.source), context.event,
@@ -4040,7 +4090,15 @@ var htmx = (function() {
4040
4090
  get: function(target, name) {
4041
4091
  if (typeof name === 'symbol') {
4042
4092
  // Forward symbol calls to the FormData itself directly
4043
- return Reflect.get(target, name)
4093
+ const result = Reflect.get(target, name)
4094
+ // Wrap in function with apply to correctly bind the FormData context, as a direct call would result in an illegal invocation error
4095
+ if (typeof result === 'function') {
4096
+ return function() {
4097
+ return result.apply(formData, arguments)
4098
+ }
4099
+ } else {
4100
+ return result
4101
+ }
4044
4102
  }
4045
4103
  if (name === 'toJSON') {
4046
4104
  // Support JSON.stringify call on proxy
@@ -4874,7 +4932,7 @@ var htmx = (function() {
4874
4932
  * @see https://htmx.org/api/#defineExtension
4875
4933
  *
4876
4934
  * @param {string} name the extension name
4877
- * @param {HtmxExtension} extension the extension definition
4935
+ * @param {Partial<HtmxExtension>} extension the extension definition
4878
4936
  */
4879
4937
  function defineExtension(name, extension) {
4880
4938
  if (extension.init) {