mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-09-30 14:31:47 +00:00
docs + config of head handling
This commit is contained in:
parent
5cdd50ebbe
commit
8b59cb9383
36
src/htmx.js
36
src/htmx.js
@ -61,7 +61,7 @@ var htmx = (function() {
|
|||||||
disableInheritance: false,
|
disableInheritance: false,
|
||||||
head : {
|
head : {
|
||||||
boost : "merge",
|
boost : "merge",
|
||||||
other: "title",
|
other: "none",
|
||||||
},
|
},
|
||||||
responseHandling: [
|
responseHandling: [
|
||||||
{ code: '204', swap: false },
|
{ code: '204', swap: false },
|
||||||
@ -1143,17 +1143,12 @@ var htmx = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleHeadTag(head, defaultStrategy) {
|
function handleHeadTag(head, strategy) {
|
||||||
|
|
||||||
if (head && htmx.config.head) {
|
|
||||||
|
|
||||||
if (defaultStrategy === "none") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (head && (strategy === "merge" || strategy === "append")) {
|
||||||
// allow new head to override merge strategy
|
// allow new head to override merge strategy
|
||||||
let elementMergeStrategy = getAttributeValue(head, "hx-head") || defaultStrategy;
|
let elementMergeStrategy = getAttributeValue(head, "hx-head") || strategy;
|
||||||
if (elementMergeStrategy === "append" || elementMergeStrategy === "merge") {
|
if (elementMergeStrategy === "merge" || elementMergeStrategy === "append") {
|
||||||
let removed = []
|
let removed = []
|
||||||
let appended = []
|
let appended = []
|
||||||
|
|
||||||
@ -2216,7 +2211,7 @@ var htmx = (function() {
|
|||||||
const historyElement = getHistoryElement()
|
const historyElement = getHistoryElement()
|
||||||
const settleInfo = makeSettleInfo(historyElement)
|
const settleInfo = makeSettleInfo(historyElement)
|
||||||
handleTitle(fragment.title);
|
handleTitle(fragment.title);
|
||||||
handleHeadTag(fragment.head, "merge");
|
handleHeadTag(fragment.head, htmx.config.head.boost);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
swapInnerHTML(historyElement, content, settleInfo)
|
swapInnerHTML(historyElement, content, settleInfo)
|
||||||
@ -2239,7 +2234,7 @@ var htmx = (function() {
|
|||||||
const historyElement = getHistoryElement()
|
const historyElement = getHistoryElement()
|
||||||
const settleInfo = makeSettleInfo(historyElement)
|
const settleInfo = makeSettleInfo(historyElement)
|
||||||
handleTitle(fragment.title);
|
handleTitle(fragment.title);
|
||||||
handleHeadTag(fragment.head, "merge");
|
handleHeadTag(fragment.head, htmx.config.head.boost);
|
||||||
swapInnerHTML(historyElement, fragment, settleInfo)
|
swapInnerHTML(historyElement, fragment, settleInfo)
|
||||||
settleImmediately(settleInfo.tasks);
|
settleImmediately(settleInfo.tasks);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
@ -2586,6 +2581,8 @@ var htmx = (function() {
|
|||||||
swapSpec.transition = value.substr(11) === 'true'
|
swapSpec.transition = value.substr(11) === 'true'
|
||||||
} else if (value.indexOf('ignoreTitle:') === 0) {
|
} else if (value.indexOf('ignoreTitle:') === 0) {
|
||||||
swapSpec.ignoreTitle = value.substr(12) === 'true'
|
swapSpec.ignoreTitle = value.substr(12) === 'true'
|
||||||
|
} else if (value.indexOf('head:') === 0) {
|
||||||
|
swapSpec.head = value.substr(5)
|
||||||
} else if (value.indexOf('scroll:') === 0) {
|
} else if (value.indexOf('scroll:') === 0) {
|
||||||
const scrollSpec = value.substr(7)
|
const scrollSpec = value.substr(7)
|
||||||
var splitSpec = scrollSpec.split(':')
|
var splitSpec = scrollSpec.split(':')
|
||||||
@ -3381,6 +3378,7 @@ var htmx = (function() {
|
|||||||
const shouldSwap = responseHandling.swap
|
const shouldSwap = responseHandling.swap
|
||||||
let isError = !!responseHandling.error
|
let isError = !!responseHandling.error
|
||||||
let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle
|
let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle
|
||||||
|
let head = responseInfo.boosted ? htmx.config.head.boost : htmx.config.head.other
|
||||||
let selectOverride = responseHandling.select
|
let selectOverride = responseHandling.select
|
||||||
if (responseHandling.target) {
|
if (responseHandling.target) {
|
||||||
responseInfo.target = querySelectorExt(elt, responseHandling.target)
|
responseInfo.target = querySelectorExt(elt, responseHandling.target)
|
||||||
@ -3408,7 +3406,8 @@ var htmx = (function() {
|
|||||||
serverResponse,
|
serverResponse,
|
||||||
isError,
|
isError,
|
||||||
ignoreTitle,
|
ignoreTitle,
|
||||||
selectOverride
|
selectOverride,
|
||||||
|
head
|
||||||
}, responseInfo)
|
}, responseInfo)
|
||||||
|
|
||||||
if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return
|
if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return
|
||||||
@ -3419,6 +3418,7 @@ var htmx = (function() {
|
|||||||
serverResponse = beforeSwapDetails.serverResponse // allow updating content
|
serverResponse = beforeSwapDetails.serverResponse // allow updating content
|
||||||
isError = beforeSwapDetails.isError // allow updating error
|
isError = beforeSwapDetails.isError // allow updating error
|
||||||
ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title
|
ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title
|
||||||
|
head = beforeSwapDetails.head // allow updating head algorithm
|
||||||
selectOverride = beforeSwapDetails.selectOverride // allow updating select override
|
selectOverride = beforeSwapDetails.selectOverride // allow updating select override
|
||||||
|
|
||||||
responseInfo.target = target // Make updated target available to response events
|
responseInfo.target = target // Make updated target available to response events
|
||||||
@ -3447,6 +3447,9 @@ var htmx = (function() {
|
|||||||
if (swapSpec.hasOwnProperty('ignoreTitle')) {
|
if (swapSpec.hasOwnProperty('ignoreTitle')) {
|
||||||
ignoreTitle = swapSpec.ignoreTitle
|
ignoreTitle = swapSpec.ignoreTitle
|
||||||
}
|
}
|
||||||
|
if (swapSpec.hasOwnProperty('head')) {
|
||||||
|
head = swapSpec.head
|
||||||
|
}
|
||||||
|
|
||||||
target.classList.add(htmx.config.swappingClass)
|
target.classList.add(htmx.config.swappingClass)
|
||||||
|
|
||||||
@ -3524,10 +3527,10 @@ var htmx = (function() {
|
|||||||
handleTitle(settleInfo.title);
|
handleTitle(settleInfo.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("Here", head)
|
||||||
// merge in new head after swap but before settle
|
// merge in new head after swap but before settle
|
||||||
if (triggerEvent(document.body, "htmx:beforeHeadMerge", {head: settleInfo.head})) {
|
if (triggerEvent(document.body, "htmx:beforeHeadMerge", {head: settleInfo.head})) {
|
||||||
handleHeadTag(settleInfo.head, responseInfo.boosted ? htmx.config.head.boost :
|
handleHeadTag(settleInfo.head, head);
|
||||||
htmx.config.head.other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) {
|
if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) {
|
||||||
@ -3642,8 +3645,9 @@ var htmx = (function() {
|
|||||||
* @param {import("./htmx").HtmxExtension} extension
|
* @param {import("./htmx").HtmxExtension} extension
|
||||||
*/
|
*/
|
||||||
function defineExtension(name, extension) {
|
function defineExtension(name, extension) {
|
||||||
|
if (name === "head-support") return; // ignore the head support extension, now integrated into htmx
|
||||||
if (extension.init) {
|
if (extension.init) {
|
||||||
extension.init(internalAPI)
|
extension.init(internalAPI);
|
||||||
}
|
}
|
||||||
extensions[name] = mergeObjects(extensionBase(), extension)
|
extensions[name] = mergeObjects(extensionBase(), extension)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<meta http-equiv="expires" content="0" />
|
<meta http-equiv="expires" content="0" />
|
||||||
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
|
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
|
||||||
<meta http-equiv="pragma" content="no-cache" />
|
<meta http-equiv="pragma" content="no-cache" />
|
||||||
<meta name="htmx-config" content='{"historyEnabled":false,"defaultSettleDelay":0,"head":false}'>
|
<meta name="htmx-config" content='{"historyEnabled":false,"defaultSettleDelay":0,"head":{"boost":"none","other":"none"}}'>
|
||||||
</head>
|
</head>
|
||||||
<body style="padding:20px;font-family: sans-serif">
|
<body style="padding:20px;font-family: sans-serif">
|
||||||
|
|
||||||
|
@ -39,6 +39,15 @@ If you want to use the new [View Transitions](https://developer.mozilla.org/en-U
|
|||||||
when a swap occurs, you can use the `transition:true` option for your swap. You can also enable this feature globally by
|
when a swap occurs, you can use the `transition:true` option for your swap. You can also enable this feature globally by
|
||||||
setting the `htmx.config.globalViewTransitions` config setting to `true`.
|
setting the `htmx.config.globalViewTransitions` config setting to `true`.
|
||||||
|
|
||||||
|
#### `head` tag handling: `head`
|
||||||
|
|
||||||
|
If you want to modify how a `head` tag found in the new content is handled, you can use the `head` modifier, with one
|
||||||
|
of the following values:
|
||||||
|
|
||||||
|
* `merge` - merge the new head tag elements into the existing element
|
||||||
|
* `append` - append the new head tag elements to the existing head tag
|
||||||
|
* `none` - ignore any new head tag elements
|
||||||
|
|
||||||
#### Timing: `swap` & `settle`
|
#### Timing: `swap` & `settle`
|
||||||
|
|
||||||
You can modify the amount of time that htmx will wait after receiving a response to swap the content
|
You can modify the amount of time that htmx will wait after receiving a response to swap the content
|
||||||
|
@ -29,6 +29,7 @@ custom_classes = "wide-content"
|
|||||||
* [confirming](#confirming)
|
* [confirming](#confirming)
|
||||||
* [inheritance](#inheritance)
|
* [inheritance](#inheritance)
|
||||||
* [boosting](#boosting)
|
* [boosting](#boosting)
|
||||||
|
* [head tag handling](#head)
|
||||||
* [websockets & SSE](#websockets-and-sse)
|
* [websockets & SSE](#websockets-and-sse)
|
||||||
* [history](#history)
|
* [history](#history)
|
||||||
* [requests & responses](#requests)
|
* [requests & responses](#requests)
|
||||||
@ -182,10 +183,6 @@ To upgrade to htmx 2.0 from htmx 1.0, you will need to do the following:
|
|||||||
`htmx.config.methodsThatUseUrlParams` to `["get"]` (it's a little crazy, but `DELETE`, according to the spec, should
|
`htmx.config.methodsThatUseUrlParams` to `["get"]` (it's a little crazy, but `DELETE`, according to the spec, should
|
||||||
use request parameters.)
|
use request parameters.)
|
||||||
* If you want to make cross-domain requests with htmx, revert `htmx.config.selfRequestsOnly` to `false`
|
* If you want to make cross-domain requests with htmx, revert `htmx.config.selfRequestsOnly` to `false`
|
||||||
* If you want to revert these to the htmx 1.x defaults, you can use the following meta tag:
|
|
||||||
```html
|
|
||||||
<meta name="htmx-config" content='{"scrollBehavior":"smooth", "methodsThatUseUrlParams":["get"], "selfRequestsOnly": false}'>
|
|
||||||
```
|
|
||||||
* Convert any `hx-on` attributes to their `hx-on:` equivalent:
|
* Convert any `hx-on` attributes to their `hx-on:` equivalent:
|
||||||
```html
|
```html
|
||||||
<button hx-get="/info" hx-on="htmx:beforeRequest: alert('Making a request!')
|
<button hx-get="/info" hx-on="htmx:beforeRequest: alert('Making a request!')
|
||||||
@ -202,6 +199,9 @@ To upgrade to htmx 2.0 from htmx 1.0, you will need to do the following:
|
|||||||
Note that you must use the kebab-case of the event name due to the fact that attributes are case-insensitive in HTML.
|
Note that you must use the kebab-case of the event name due to the fact that attributes are case-insensitive in HTML.
|
||||||
```
|
```
|
||||||
* The `htmx.makeFragment()` method now **always** returns a `DocumentFragment` rather than either an `Element` or `DocumentFragment`
|
* The `htmx.makeFragment()` method now **always** returns a `DocumentFragment` rather than either an `Element` or `DocumentFragment`
|
||||||
|
* If you are using htmx in a module setting, we now provide module-type specific files for all three of the major
|
||||||
|
JavaScript module types: `/dist/htmx.esm.js`, `/dist/htmx.umd.js` & `/dist/htmx.amd.js`
|
||||||
|
* htmx 2.0 offers [automatic head merging](#head-support) with boosted links. If you do not want this behavior, set you can set `htmx.config.head.boosted` to `"none"`
|
||||||
|
|
||||||
IE is no longer supported in htmx 2.0, but htmx 1.x continues to support IE and will be supported for the foreseeable
|
IE is no longer supported in htmx 2.0, but htmx 1.x continues to support IE and will be supported for the foreseeable
|
||||||
future.
|
future.
|
||||||
@ -779,6 +779,46 @@ Here is an example:
|
|||||||
|
|
||||||
The anchor tag in this div will issue an AJAX `GET` request to `/blog` and swap the response into the `body` tag.
|
The anchor tag in this div will issue an AJAX `GET` request to `/blog` and swap the response into the `body` tag.
|
||||||
|
|
||||||
|
### `head` tag support
|
||||||
|
|
||||||
|
In boosted requests, if a head tag is detected in the response, htmx will automatically synchronize the content of
|
||||||
|
the current head tag with the new content. This means that elements that are already found in the current head will
|
||||||
|
be left alone (and, therefore, not trigger another request), but new elements found in the new header will be added
|
||||||
|
to the existing header tag. Elements that are not found in the new head will be removed from the existing head tag.
|
||||||
|
|
||||||
|
This allows you to include page-specific header related elements and have them added or removed via boosted requests.
|
||||||
|
|
||||||
|
htmx also supports an "append" mode, that will simply append the content of the new head tag to the current head, if
|
||||||
|
the new content is not already in it. You can control the mode that htmx will use with the `hx-head` attribute on
|
||||||
|
the head tag in the *new* content:
|
||||||
|
|
||||||
|
* `merge` - follow the merging algorithm outlined above
|
||||||
|
* `append` - append elements that do not exist in it to the existing head, but don't remove any elements
|
||||||
|
|
||||||
|
#### Controlling Merge Behavior Per Element
|
||||||
|
|
||||||
|
You may also control merging behavior of individual elements with the following attributes:
|
||||||
|
|
||||||
|
* If you place `hx-head="re-eval"` on a head element, it will be re-added (removed and appended) to the head tag on every
|
||||||
|
request, even if it already exists. This can be useful to execute a script on every htmx request, for example.
|
||||||
|
* If you place `hx-preserve="true"` on an element, it will never be removed from the head, regardless
|
||||||
|
|
||||||
|
#### Configuring Boost & Non-Boost `head` behavior
|
||||||
|
|
||||||
|
You can configure the default head behavior by setting the `boost` and `other` attributes in the `htmx.config.head` object,
|
||||||
|
using the following values:
|
||||||
|
|
||||||
|
* `merge` - merge the new head tag elements into the existing element
|
||||||
|
* `append` - append the new head tag elements to the existing head tag
|
||||||
|
* `none` - ignore any new head tag elements
|
||||||
|
|
||||||
|
By default, `htmx.config.head.boost` is `merge` and will apply to boosted links and forms.
|
||||||
|
|
||||||
|
`htmx.config.head.other` will apply to non-boosted requests, and defaults to `none` (that is, new head information) will
|
||||||
|
be ignored.
|
||||||
|
|
||||||
|
You can also configure the head behavior using the [`hx-swap`](/attributes/hx-swap) attribute's `head` option.
|
||||||
|
|
||||||
### Progressive Enhancement {#progressive_enhancement}
|
### Progressive Enhancement {#progressive_enhancement}
|
||||||
|
|
||||||
A feature of `hx-boost` is that it degrades gracefully if javascript is not enabled: the links and forms continue
|
A feature of `hx-boost` is that it degrades gracefully if javascript is not enabled: the links and forms continue
|
||||||
|
Loading…
x
Reference in New Issue
Block a user