mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-10-02 15:25:26 +00:00
Fix handling of file input values passed to htmx.ajax
This commit is contained in:
parent
7851c18904
commit
39a94263cb
@ -8,14 +8,15 @@
|
||||
- Fix target and source elements sent to `selectAndSwap` during the **SSE** swapping process that were inverted in the original code, now allowing to properly use `hx-target` for example to specify which element to swap with SSE
|
||||
- [SSE swap listeners](https://htmx.org/attributes/hx-sse/) are now removed from the event sources when the associated element gets removed from the page
|
||||
- Values passed along a `DELETE` request are encoded as URL parameters _(as for a `GET` request)_ instead of being sent as form data
|
||||
- The [`Content-Type`](https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Content-Type) header is no longer overridden to `application/x-www-form-urlencoded` when using [`htmx.ajax()`](https://htmx.org/api/#ajax) method _(HTMX would by default override it for any non-GET request on an element that doesn't define the `hx-encoding` attribute, but one might want to define this header in their AJAX request using the `context.headers` property)_
|
||||
- The [`Content-Type`](https://developer.mozilla.org/en/docs/Web/HTTP/Headers/Content-Type) header is no longer overridden to `application/x-www-form-urlencoded` when using [`htmx.ajax()`](https://htmx.org/api/#ajax) method _(HTMX would by default override it for any non-GET request on an element that doesn't define the [`hx-encoding`](https://htmx.org/attributes/hx-encoding/) attribute, but one might want to define this header in their AJAX request using the `context.headers` property)_
|
||||
- [`htmx.ajax()`](https://htmx.org/api/#ajax) now correctly handles files passed to it through the `context.values` property _(HTMX would by default override the content type to `application/x-www-form-urlencoded` instead of letting [xhr.send](https://xhr.spec.whatwg.org/#the-send()-method) deduce the multipart/form-data content type itself + it would only use the values of the [`hx-encoding`](https://htmx.org/attributes/hx-encoding/) and [`enctype`](https://developer.mozilla.org/en/docs/Web/API/HTMLFormElement/enctype), thus ignore the fact that the payload contains file input values and should be treated as `multipart/form-data`)_
|
||||
## Changes
|
||||
- The htmx-indicator is not hidden on request's response if the response has a `HX-Redirect` header set (just a personal visual preference)
|
||||
- If the target specified to [`htmx.ajax()`](https://htmx.org/api/#ajax) (and so the `targetOverride` passed to `issueAjaxRequest()`) can't be found, an error is thrown (instead of the HTMX default implementation that crawls the hierarchy to find the first `hx-target` specified on a parent element as a fallback)
|
||||
- In the default HTMX implementation, elements that have an ID have a special treatment during swapping ; if an element with an ID is about to be inserted, and to replace another element with the same ID, for a reason I ignore, HTMX clones the old elements "settling attributes" _(that are, by default, `class`, `style`, `width` & `height`)_ into the new element, then restores the new element initial attributes after the settling. My problem with this ; using a [MutationObserver](https://developer.mozilla.org/en/docs/Web/API/MutationObserver) to apply style to newly added nodes _(for example a line that should be positionned at current local time with a line of JS in a calendar)_ results in those modifications being reverted by HTMX after the settling. Since this cloning step appears useless to me (maybe am I wrong though ?), I got rid of it here, as well as the `attributesToSettle` property that was only used for that purpose.
|
||||
- When an HTMX error is logged, the `detail` context object passed along in the internal functions is now included in the log, for an easier debugging. This way, a `hx-targetError` for example, will also log the actual target that HTMX was trying to retrieve.
|
||||
- The attribute `hx-push-url` is no longer inherited by default by children elements. You can specify `hx-push-url="inherit"` on children elements though, to inherit the value from the closest parent that defines a `hx-push-url`.
|
||||
- HTMX uses `writeLayout` and `readLayout` _(more details below)_ internally to postpone the elements clean up & settling [to the next animation frame](https://developer.mozilla.org/fr/docs/Web/API/Window/requestAnimationFrame), so the swap function returns faster _(now takes roughly half the time)_ and the browser can update the DOM _(and the page layout display)_ sooner, providing a better visual experience.
|
||||
- HTMX uses `writeLayout` and `readLayout` _(more details below)_ internally to postpone the elements clean up & settling [to the next animation frame](https://developer.mozilla.org/en/docs/Web/API/Window/requestAnimationFrame), so the swap function returns faster _(now takes roughly half the time)_ and the browser can update the DOM _(and the page layout display)_ sooner, providing a better visual experience.
|
||||
- When using the [`hx-swap`](https://htmx.org/attributes/hx-swap/) attribute set to `"none"`, it's no longer required to have a value defined for the [`hx-target`](https://htmx.org/attributes/hx-target/) attribute _(in this case, simply no element will trigger the [htmx:beforeSwap](https://htmx.org/events/#htmx:beforeSwap) event, nor being added/removed the [swapping class](https://htmx.org/reference/#classes))_
|
||||
## Additions
|
||||
- `hx-error-target` and `hx-error-swap` attributes to allow swapping server's reponse on error (i.e request with a `status >= 300`). Those attributes behave exactly like, respectively, [hx-target](https://htmx.org/attributes/hx-target/) and [hx-swap](https://htmx.org/attributes/hx-swap/)
|
||||
@ -26,4 +27,4 @@
|
||||
- The [`htmx:beforeOnLoad`](https://htmx.org/events/#htmx:beforeOnLoad), [`htmx:beforeSwap`](https://htmx.org/events/#htmx:beforeSwap), [`htmx:afterSwap`](https://htmx.org/events/#htmx:afterSwap), [`htmx:afterSettle`](https://htmx.org/events/#htmx:afterSettle), [`htmx:swapError`](https://htmx.org/events/#htmx:swapError), [`htmx:afterRequest`](https://htmx.org/events/#htmx:afterRequest), [`htmx:afterOnLoad`](https://htmx.org/events/#htmx:afterOnLoad), [`htmx:onLoadError`](https://htmx.org/events/#htmx:onLoadError) events are now passed an additional property `isError` in the event's `detail` property, which indicates if the request's response has an error status _(ie a code >= 400)_
|
||||
- The `hx-target` attribute accepts 2 new values : `next-sibling` (which targets the [next sibling element](https://developer.mozilla.org/en-US/docs/Web/API/Element/nextElementSibling)) and `previous-sibling` (which targets the [previous sibling element](https://developer.mozilla.org/en-US/docs/Web/API/Element/previousElementSibling))
|
||||
- The HTMX API now provides the methods `readLayout` and `writeLayout`, to execute layout read/write operations while avoiding [layout thrashing](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing#avoid_layout_thrashing)
|
||||
- The HTMX API now provides the method `resizeSelect`, which takes a [select HTML element](https://developer.mozilla.org/fr/docs/Web/HTML/Element/select) as parameter, and resizes it so it fits its selected option
|
||||
- The HTMX API now provides the method `resizeSelect`, which takes a [select HTML element](https://developer.mozilla.org/en/docs/Web/HTML/Element/select) as parameter, and resizes it so it fits its selected option
|
||||
|
19
dist/htmx.js
vendored
19
dist/htmx.js
vendored
@ -2352,6 +2352,20 @@ return (function () {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* valuesContainAnyFile returns true if any of the values is a File input value
|
||||
* @param {Object} inputValues
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function valuesContainAnyFile(inputValues) {
|
||||
for (var name in inputValues) {
|
||||
if (inputValues[name] instanceof File) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function isAnchorLink(elt) {
|
||||
return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0
|
||||
}
|
||||
@ -2433,7 +2447,8 @@ return (function () {
|
||||
return encodedParameters;
|
||||
} else {
|
||||
if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" ||
|
||||
(matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) {
|
||||
(matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data") ||
|
||||
valuesContainAnyFile(filteredParameters)) {
|
||||
return makeFormData(filteredParameters);
|
||||
} else {
|
||||
return urlEncode(filteredParameters);
|
||||
@ -2773,7 +2788,7 @@ return (function () {
|
||||
var allParameters = mergeObjects(rawParameters, expressionVars);
|
||||
var filteredParameters = filterValues(allParameters, elt);
|
||||
|
||||
if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null && !headers["Content-Type"]) {
|
||||
if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null && !headers["Content-Type"] && !valuesContainAnyFile(filteredParameters)) {
|
||||
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
|
2
dist/htmx.min.js
vendored
2
dist/htmx.min.js
vendored
File diff suppressed because one or more lines are too long
19
src/htmx.js
19
src/htmx.js
@ -2352,6 +2352,20 @@ return (function () {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* valuesContainAnyFile returns true if any of the values is a File input value
|
||||
* @param {Object} inputValues
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function valuesContainAnyFile(inputValues) {
|
||||
for (var name in inputValues) {
|
||||
if (inputValues[name] instanceof File) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function isAnchorLink(elt) {
|
||||
return getRawAttribute(elt, 'href') && getRawAttribute(elt, 'href').indexOf("#") >=0
|
||||
}
|
||||
@ -2433,7 +2447,8 @@ return (function () {
|
||||
return encodedParameters;
|
||||
} else {
|
||||
if (getClosestAttributeValue(elt, "hx-encoding") === "multipart/form-data" ||
|
||||
(matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data")) {
|
||||
(matches(elt, "form") && getRawAttribute(elt, 'enctype') === "multipart/form-data") ||
|
||||
valuesContainAnyFile(filteredParameters)) {
|
||||
return makeFormData(filteredParameters);
|
||||
} else {
|
||||
return urlEncode(filteredParameters);
|
||||
@ -2773,7 +2788,7 @@ return (function () {
|
||||
var allParameters = mergeObjects(rawParameters, expressionVars);
|
||||
var filteredParameters = filterValues(allParameters, elt);
|
||||
|
||||
if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null && !headers["Content-Type"]) {
|
||||
if (verb !== 'get' && getClosestAttributeValue(elt, "hx-encoding") == null && !headers["Content-Type"] && !valuesContainAnyFile(filteredParameters)) {
|
||||
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user