htmx.org 2.0.0-beta2 → 2.0.0-beta4

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/dist/htmx.cjs.js CHANGED
@@ -164,6 +164,12 @@ var htmx = (function() {
164
164
  * @default ''
165
165
  */
166
166
  inlineScriptNonce: '',
167
+ /**
168
+ * If set, the nonce will be added to inline styles.
169
+ * @type string
170
+ * @default ''
171
+ */
172
+ inlineStyleNonce: '',
167
173
  /**
168
174
  * The attributes to settle during the settling phase.
169
175
  * @type string[]
@@ -271,7 +277,7 @@ var htmx = (function() {
271
277
  parseInterval: null,
272
278
  /** @type {typeof internalEval} */
273
279
  _: null,
274
- version: '2.0a'
280
+ version: '2.0.0-beta4'
275
281
  }
276
282
  // Tsc madness part 2
277
283
  htmx.onLoad = onLoadHelper
@@ -2251,6 +2257,13 @@ var htmx = (function() {
2251
2257
  getRawAttribute(elt, 'href').indexOf('#') !== 0
2252
2258
  }
2253
2259
 
2260
+ /**
2261
+ * @param {Element} elt
2262
+ */
2263
+ function eltIsDisabled(elt) {
2264
+ return closest(elt, htmx.config.disableSelector)
2265
+ }
2266
+
2254
2267
  /**
2255
2268
  * @param {Element} elt
2256
2269
  * @param {HtmxNodeInternalData} nodeData
@@ -2273,7 +2286,7 @@ var htmx = (function() {
2273
2286
  triggerSpecs.forEach(function(triggerSpec) {
2274
2287
  addEventListener(elt, function(node, evt) {
2275
2288
  const elt = asElement(node)
2276
- if (closest(elt, htmx.config.disableSelector)) {
2289
+ if (eltIsDisabled(elt)) {
2277
2290
  cleanUpElement(elt)
2278
2291
  return
2279
2292
  }
@@ -2602,19 +2615,28 @@ var htmx = (function() {
2602
2615
  * @param {Node} elt
2603
2616
  * @returns {Element[]}
2604
2617
  */
2605
- function findHxOnWildcardElements(elt) {
2618
+ const HX_ON_QUERY = new XPathEvaluator()
2619
+ .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
2620
+ ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]')
2621
+
2622
+ function processHXOnRoot(elt, elements) {
2623
+ if (shouldProcessHxOn(elt)) {
2624
+ elements.push(asElement(elt))
2625
+ }
2626
+ const iter = HX_ON_QUERY.evaluate(elt)
2606
2627
  let node = null
2628
+ while (node = iter.iterateNext()) elements.push(asElement(node))
2629
+ }
2630
+
2631
+ function findHxOnWildcardElements(elt) {
2607
2632
  /** @type {Element[]} */
2608
2633
  const elements = []
2609
-
2610
- if (!(elt instanceof ShadowRoot)) {
2611
- if (shouldProcessHxOn(elt)) {
2612
- elements.push(asElement(elt))
2634
+ if (elt instanceof DocumentFragment) {
2635
+ for (const child of elt.childNodes) {
2636
+ processHXOnRoot(child, elements)
2613
2637
  }
2614
-
2615
- const iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
2616
- ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt)
2617
- while (node = iter.iterateNext()) elements.push(asElement(node))
2638
+ } else {
2639
+ processHXOnRoot(elt, elements)
2618
2640
  }
2619
2641
  return elements
2620
2642
  }
@@ -2626,8 +2648,21 @@ var htmx = (function() {
2626
2648
  function findElementsToProcess(elt) {
2627
2649
  if (elt.querySelectorAll) {
2628
2650
  const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]'
2651
+
2652
+ const extensionSelectors = []
2653
+ for (const e in extensions) {
2654
+ const extension = extensions[e]
2655
+ if (extension.getSelectors) {
2656
+ var selectors = extension.getSelectors()
2657
+ if (selectors) {
2658
+ extensionSelectors.push(selectors)
2659
+ }
2660
+ }
2661
+ }
2662
+
2629
2663
  const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," +
2630
- ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]')
2664
+ ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join(''))
2665
+
2631
2666
  return results
2632
2667
  } else {
2633
2668
  return []
@@ -2686,7 +2721,7 @@ var htmx = (function() {
2686
2721
  }
2687
2722
 
2688
2723
  /**
2689
- * @param {EventTarget} elt
2724
+ * @param {Element} elt
2690
2725
  * @param {string} eventName
2691
2726
  * @param {string} code
2692
2727
  */
@@ -2699,6 +2734,9 @@ var htmx = (function() {
2699
2734
  /** @type EventListener */
2700
2735
  const listener = function(e) {
2701
2736
  maybeEval(elt, function() {
2737
+ if (eltIsDisabled(elt)) {
2738
+ return
2739
+ }
2702
2740
  if (!func) {
2703
2741
  func = new Function('event', code)
2704
2742
  }
@@ -3308,6 +3346,9 @@ var htmx = (function() {
3308
3346
  }
3309
3347
  })
3310
3348
  new FormData(elt).forEach(function(value, name) {
3349
+ if (value instanceof File && value.name === '') {
3350
+ return // ignore no-name files
3351
+ }
3311
3352
  addValueToFormData(name, value, formData)
3312
3353
  })
3313
3354
  }
@@ -3591,7 +3632,9 @@ var htmx = (function() {
3591
3632
  return encodedParameters
3592
3633
  } else {
3593
3634
  if (usesFormData(elt)) {
3594
- return formDataFromObject(filteredParameters)
3635
+ // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy
3636
+ // See https://github.com/bigskysoftware/htmx/issues/2317
3637
+ return overrideFormData(new FormData(), formDataFromObject(filteredParameters))
3595
3638
  } else {
3596
3639
  return urlEncode(filteredParameters)
3597
3640
  }
@@ -4743,6 +4786,7 @@ var htmx = (function() {
4743
4786
  function extensionBase() {
4744
4787
  return {
4745
4788
  init: function(api) { return null },
4789
+ getSelectors: function() { return null },
4746
4790
  onEvent: function(name, evt) { return true },
4747
4791
  transformResponse: function(text, xhr, elt) { return text },
4748
4792
  isInlineSwap: function(swapStyle) { return false },
@@ -4841,8 +4885,9 @@ var htmx = (function() {
4841
4885
 
4842
4886
  function insertIndicatorStyles() {
4843
4887
  if (htmx.config.includeIndicatorStyles !== false) {
4888
+ const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : ''
4844
4889
  getDocument().head.insertAdjacentHTML('beforeend',
4845
- '<style>\
4890
+ '<style' + nonceAttribute + '>\
4846
4891
  .' + htmx.config.indicatorClass + '{opacity:0}\
4847
4892
  .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\
4848
4893
  .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\
package/dist/htmx.esm.js CHANGED
@@ -164,6 +164,12 @@ var htmx = (function() {
164
164
  * @default ''
165
165
  */
166
166
  inlineScriptNonce: '',
167
+ /**
168
+ * If set, the nonce will be added to inline styles.
169
+ * @type string
170
+ * @default ''
171
+ */
172
+ inlineStyleNonce: '',
167
173
  /**
168
174
  * The attributes to settle during the settling phase.
169
175
  * @type string[]
@@ -271,7 +277,7 @@ var htmx = (function() {
271
277
  parseInterval: null,
272
278
  /** @type {typeof internalEval} */
273
279
  _: null,
274
- version: '2.0a'
280
+ version: '2.0.0-beta4'
275
281
  }
276
282
  // Tsc madness part 2
277
283
  htmx.onLoad = onLoadHelper
@@ -2251,6 +2257,13 @@ var htmx = (function() {
2251
2257
  getRawAttribute(elt, 'href').indexOf('#') !== 0
2252
2258
  }
2253
2259
 
2260
+ /**
2261
+ * @param {Element} elt
2262
+ */
2263
+ function eltIsDisabled(elt) {
2264
+ return closest(elt, htmx.config.disableSelector)
2265
+ }
2266
+
2254
2267
  /**
2255
2268
  * @param {Element} elt
2256
2269
  * @param {HtmxNodeInternalData} nodeData
@@ -2273,7 +2286,7 @@ var htmx = (function() {
2273
2286
  triggerSpecs.forEach(function(triggerSpec) {
2274
2287
  addEventListener(elt, function(node, evt) {
2275
2288
  const elt = asElement(node)
2276
- if (closest(elt, htmx.config.disableSelector)) {
2289
+ if (eltIsDisabled(elt)) {
2277
2290
  cleanUpElement(elt)
2278
2291
  return
2279
2292
  }
@@ -2602,19 +2615,28 @@ var htmx = (function() {
2602
2615
  * @param {Node} elt
2603
2616
  * @returns {Element[]}
2604
2617
  */
2605
- function findHxOnWildcardElements(elt) {
2618
+ const HX_ON_QUERY = new XPathEvaluator()
2619
+ .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
2620
+ ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]')
2621
+
2622
+ function processHXOnRoot(elt, elements) {
2623
+ if (shouldProcessHxOn(elt)) {
2624
+ elements.push(asElement(elt))
2625
+ }
2626
+ const iter = HX_ON_QUERY.evaluate(elt)
2606
2627
  let node = null
2628
+ while (node = iter.iterateNext()) elements.push(asElement(node))
2629
+ }
2630
+
2631
+ function findHxOnWildcardElements(elt) {
2607
2632
  /** @type {Element[]} */
2608
2633
  const elements = []
2609
-
2610
- if (!(elt instanceof ShadowRoot)) {
2611
- if (shouldProcessHxOn(elt)) {
2612
- elements.push(asElement(elt))
2634
+ if (elt instanceof DocumentFragment) {
2635
+ for (const child of elt.childNodes) {
2636
+ processHXOnRoot(child, elements)
2613
2637
  }
2614
-
2615
- const iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
2616
- ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt)
2617
- while (node = iter.iterateNext()) elements.push(asElement(node))
2638
+ } else {
2639
+ processHXOnRoot(elt, elements)
2618
2640
  }
2619
2641
  return elements
2620
2642
  }
@@ -2626,8 +2648,21 @@ var htmx = (function() {
2626
2648
  function findElementsToProcess(elt) {
2627
2649
  if (elt.querySelectorAll) {
2628
2650
  const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]'
2651
+
2652
+ const extensionSelectors = []
2653
+ for (const e in extensions) {
2654
+ const extension = extensions[e]
2655
+ if (extension.getSelectors) {
2656
+ var selectors = extension.getSelectors()
2657
+ if (selectors) {
2658
+ extensionSelectors.push(selectors)
2659
+ }
2660
+ }
2661
+ }
2662
+
2629
2663
  const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," +
2630
- ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]')
2664
+ ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join(''))
2665
+
2631
2666
  return results
2632
2667
  } else {
2633
2668
  return []
@@ -2686,7 +2721,7 @@ var htmx = (function() {
2686
2721
  }
2687
2722
 
2688
2723
  /**
2689
- * @param {EventTarget} elt
2724
+ * @param {Element} elt
2690
2725
  * @param {string} eventName
2691
2726
  * @param {string} code
2692
2727
  */
@@ -2699,6 +2734,9 @@ var htmx = (function() {
2699
2734
  /** @type EventListener */
2700
2735
  const listener = function(e) {
2701
2736
  maybeEval(elt, function() {
2737
+ if (eltIsDisabled(elt)) {
2738
+ return
2739
+ }
2702
2740
  if (!func) {
2703
2741
  func = new Function('event', code)
2704
2742
  }
@@ -3308,6 +3346,9 @@ var htmx = (function() {
3308
3346
  }
3309
3347
  })
3310
3348
  new FormData(elt).forEach(function(value, name) {
3349
+ if (value instanceof File && value.name === '') {
3350
+ return // ignore no-name files
3351
+ }
3311
3352
  addValueToFormData(name, value, formData)
3312
3353
  })
3313
3354
  }
@@ -3591,7 +3632,9 @@ var htmx = (function() {
3591
3632
  return encodedParameters
3592
3633
  } else {
3593
3634
  if (usesFormData(elt)) {
3594
- return formDataFromObject(filteredParameters)
3635
+ // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy
3636
+ // See https://github.com/bigskysoftware/htmx/issues/2317
3637
+ return overrideFormData(new FormData(), formDataFromObject(filteredParameters))
3595
3638
  } else {
3596
3639
  return urlEncode(filteredParameters)
3597
3640
  }
@@ -4743,6 +4786,7 @@ var htmx = (function() {
4743
4786
  function extensionBase() {
4744
4787
  return {
4745
4788
  init: function(api) { return null },
4789
+ getSelectors: function() { return null },
4746
4790
  onEvent: function(name, evt) { return true },
4747
4791
  transformResponse: function(text, xhr, elt) { return text },
4748
4792
  isInlineSwap: function(swapStyle) { return false },
@@ -4841,8 +4885,9 @@ var htmx = (function() {
4841
4885
 
4842
4886
  function insertIndicatorStyles() {
4843
4887
  if (htmx.config.includeIndicatorStyles !== false) {
4888
+ const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : ''
4844
4889
  getDocument().head.insertAdjacentHTML('beforeend',
4845
- '<style>\
4890
+ '<style' + nonceAttribute + '>\
4846
4891
  .' + htmx.config.indicatorClass + '{opacity:0}\
4847
4892
  .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\
4848
4893
  .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\
@@ -5082,4 +5127,4 @@ var htmx = (function() {
5082
5127
  * @property {(swapStyle: HtmxSwapStyle, target: Element, fragment: Node, settleInfo: HtmxSettleInfo) => boolean} handleSwap
5083
5128
  * @property {(xhr: XMLHttpRequest, parameters: FormData, elt: Element) => *|string|null} encodeParameters
5084
5129
  */
5085
- export { htmx }
5130
+ export default htmx
package/dist/htmx.js CHANGED
@@ -164,6 +164,12 @@ var htmx = (function() {
164
164
  * @default ''
165
165
  */
166
166
  inlineScriptNonce: '',
167
+ /**
168
+ * If set, the nonce will be added to inline styles.
169
+ * @type string
170
+ * @default ''
171
+ */
172
+ inlineStyleNonce: '',
167
173
  /**
168
174
  * The attributes to settle during the settling phase.
169
175
  * @type string[]
@@ -271,7 +277,7 @@ var htmx = (function() {
271
277
  parseInterval: null,
272
278
  /** @type {typeof internalEval} */
273
279
  _: null,
274
- version: '2.0a'
280
+ version: '2.0.0-beta4'
275
281
  }
276
282
  // Tsc madness part 2
277
283
  htmx.onLoad = onLoadHelper
@@ -2251,6 +2257,13 @@ var htmx = (function() {
2251
2257
  getRawAttribute(elt, 'href').indexOf('#') !== 0
2252
2258
  }
2253
2259
 
2260
+ /**
2261
+ * @param {Element} elt
2262
+ */
2263
+ function eltIsDisabled(elt) {
2264
+ return closest(elt, htmx.config.disableSelector)
2265
+ }
2266
+
2254
2267
  /**
2255
2268
  * @param {Element} elt
2256
2269
  * @param {HtmxNodeInternalData} nodeData
@@ -2273,7 +2286,7 @@ var htmx = (function() {
2273
2286
  triggerSpecs.forEach(function(triggerSpec) {
2274
2287
  addEventListener(elt, function(node, evt) {
2275
2288
  const elt = asElement(node)
2276
- if (closest(elt, htmx.config.disableSelector)) {
2289
+ if (eltIsDisabled(elt)) {
2277
2290
  cleanUpElement(elt)
2278
2291
  return
2279
2292
  }
@@ -2602,19 +2615,28 @@ var htmx = (function() {
2602
2615
  * @param {Node} elt
2603
2616
  * @returns {Element[]}
2604
2617
  */
2605
- function findHxOnWildcardElements(elt) {
2618
+ const HX_ON_QUERY = new XPathEvaluator()
2619
+ .createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
2620
+ ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]')
2621
+
2622
+ function processHXOnRoot(elt, elements) {
2623
+ if (shouldProcessHxOn(elt)) {
2624
+ elements.push(asElement(elt))
2625
+ }
2626
+ const iter = HX_ON_QUERY.evaluate(elt)
2606
2627
  let node = null
2628
+ while (node = iter.iterateNext()) elements.push(asElement(node))
2629
+ }
2630
+
2631
+ function findHxOnWildcardElements(elt) {
2607
2632
  /** @type {Element[]} */
2608
2633
  const elements = []
2609
-
2610
- if (!(elt instanceof ShadowRoot)) {
2611
- if (shouldProcessHxOn(elt)) {
2612
- elements.push(asElement(elt))
2634
+ if (elt instanceof DocumentFragment) {
2635
+ for (const child of elt.childNodes) {
2636
+ processHXOnRoot(child, elements)
2613
2637
  }
2614
-
2615
- const iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
2616
- ' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt)
2617
- while (node = iter.iterateNext()) elements.push(asElement(node))
2638
+ } else {
2639
+ processHXOnRoot(elt, elements)
2618
2640
  }
2619
2641
  return elements
2620
2642
  }
@@ -2626,8 +2648,21 @@ var htmx = (function() {
2626
2648
  function findElementsToProcess(elt) {
2627
2649
  if (elt.querySelectorAll) {
2628
2650
  const boostedSelector = ', [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]'
2651
+
2652
+ const extensionSelectors = []
2653
+ for (const e in extensions) {
2654
+ const extension = extensions[e]
2655
+ if (extension.getSelectors) {
2656
+ var selectors = extension.getSelectors()
2657
+ if (selectors) {
2658
+ extensionSelectors.push(selectors)
2659
+ }
2660
+ }
2661
+ }
2662
+
2629
2663
  const results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," +
2630
- ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]')
2664
+ ' [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]' + extensionSelectors.flat().map(s => ', ' + s).join(''))
2665
+
2631
2666
  return results
2632
2667
  } else {
2633
2668
  return []
@@ -2686,7 +2721,7 @@ var htmx = (function() {
2686
2721
  }
2687
2722
 
2688
2723
  /**
2689
- * @param {EventTarget} elt
2724
+ * @param {Element} elt
2690
2725
  * @param {string} eventName
2691
2726
  * @param {string} code
2692
2727
  */
@@ -2699,6 +2734,9 @@ var htmx = (function() {
2699
2734
  /** @type EventListener */
2700
2735
  const listener = function(e) {
2701
2736
  maybeEval(elt, function() {
2737
+ if (eltIsDisabled(elt)) {
2738
+ return
2739
+ }
2702
2740
  if (!func) {
2703
2741
  func = new Function('event', code)
2704
2742
  }
@@ -3308,6 +3346,9 @@ var htmx = (function() {
3308
3346
  }
3309
3347
  })
3310
3348
  new FormData(elt).forEach(function(value, name) {
3349
+ if (value instanceof File && value.name === '') {
3350
+ return // ignore no-name files
3351
+ }
3311
3352
  addValueToFormData(name, value, formData)
3312
3353
  })
3313
3354
  }
@@ -3591,7 +3632,9 @@ var htmx = (function() {
3591
3632
  return encodedParameters
3592
3633
  } else {
3593
3634
  if (usesFormData(elt)) {
3594
- return formDataFromObject(filteredParameters)
3635
+ // Force conversion to an actual FormData object in case filteredParameters is a formDataProxy
3636
+ // See https://github.com/bigskysoftware/htmx/issues/2317
3637
+ return overrideFormData(new FormData(), formDataFromObject(filteredParameters))
3595
3638
  } else {
3596
3639
  return urlEncode(filteredParameters)
3597
3640
  }
@@ -4743,6 +4786,7 @@ var htmx = (function() {
4743
4786
  function extensionBase() {
4744
4787
  return {
4745
4788
  init: function(api) { return null },
4789
+ getSelectors: function() { return null },
4746
4790
  onEvent: function(name, evt) { return true },
4747
4791
  transformResponse: function(text, xhr, elt) { return text },
4748
4792
  isInlineSwap: function(swapStyle) { return false },
@@ -4841,8 +4885,9 @@ var htmx = (function() {
4841
4885
 
4842
4886
  function insertIndicatorStyles() {
4843
4887
  if (htmx.config.includeIndicatorStyles !== false) {
4888
+ const nonceAttribute = htmx.config.inlineStyleNonce ? ` nonce="${htmx.config.inlineStyleNonce}"` : ''
4844
4889
  getDocument().head.insertAdjacentHTML('beforeend',
4845
- '<style>\
4890
+ '<style' + nonceAttribute + '>\
4846
4891
  .' + htmx.config.indicatorClass + '{opacity:0}\
4847
4892
  .' + htmx.config.requestClass + ' .' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\
4848
4893
  .' + htmx.config.requestClass + '.' + htmx.config.indicatorClass + '{opacity:1; transition: opacity 200ms ease-in;}\