Skip to content

Commit

Permalink
docs + config of head handling
Browse files Browse the repository at this point in the history
  • Loading branch information
1cg committed Jan 5, 2024
1 parent 5cdd50e commit 8b59cb9
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 21 deletions.
36 changes: 20 additions & 16 deletions src/htmx.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ var htmx = (function() {
disableInheritance: false,
head : {
boost : "merge",
other: "title",
other: "none",
},
responseHandling: [
{ code: '204', swap: false },
Expand Down Expand Up @@ -1143,17 +1143,12 @@ var htmx = (function() {
}
}

function handleHeadTag(head, defaultStrategy) {

if (head && htmx.config.head) {

if (defaultStrategy === "none") {
return
}
function handleHeadTag(head, strategy) {

if (head && (strategy === "merge" || strategy === "append")) {
// allow new head to override merge strategy
let elementMergeStrategy = getAttributeValue(head, "hx-head") || defaultStrategy;
if (elementMergeStrategy === "append" || elementMergeStrategy === "merge") {
let elementMergeStrategy = getAttributeValue(head, "hx-head") || strategy;
if (elementMergeStrategy === "merge" || elementMergeStrategy === "append") {
let removed = []
let appended = []

Expand Down Expand Up @@ -2216,7 +2211,7 @@ var htmx = (function() {
const historyElement = getHistoryElement()
const settleInfo = makeSettleInfo(historyElement)
handleTitle(fragment.title);
handleHeadTag(fragment.head, "merge");
handleHeadTag(fragment.head, htmx.config.head.boost);

// @ts-ignore
swapInnerHTML(historyElement, content, settleInfo)
Expand All @@ -2239,7 +2234,7 @@ var htmx = (function() {
const historyElement = getHistoryElement()
const settleInfo = makeSettleInfo(historyElement)
handleTitle(fragment.title);
handleHeadTag(fragment.head, "merge");
handleHeadTag(fragment.head, htmx.config.head.boost);
swapInnerHTML(historyElement, fragment, settleInfo)
settleImmediately(settleInfo.tasks);
setTimeout(function() {
Expand Down Expand Up @@ -2586,6 +2581,8 @@ var htmx = (function() {
swapSpec.transition = value.substr(11) === 'true'
} else if (value.indexOf('ignoreTitle:') === 0) {
swapSpec.ignoreTitle = value.substr(12) === 'true'
} else if (value.indexOf('head:') === 0) {
swapSpec.head = value.substr(5)
} else if (value.indexOf('scroll:') === 0) {
const scrollSpec = value.substr(7)
var splitSpec = scrollSpec.split(':')
Expand Down Expand Up @@ -3381,6 +3378,7 @@ var htmx = (function() {
const shouldSwap = responseHandling.swap
let isError = !!responseHandling.error
let ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle
let head = responseInfo.boosted ? htmx.config.head.boost : htmx.config.head.other
let selectOverride = responseHandling.select
if (responseHandling.target) {
responseInfo.target = querySelectorExt(elt, responseHandling.target)
Expand Down Expand Up @@ -3408,7 +3406,8 @@ var htmx = (function() {
serverResponse,
isError,
ignoreTitle,
selectOverride
selectOverride,
head
}, responseInfo)

if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return
Expand All @@ -3419,6 +3418,7 @@ var htmx = (function() {
serverResponse = beforeSwapDetails.serverResponse // allow updating content
isError = beforeSwapDetails.isError // allow updating error
ignoreTitle = beforeSwapDetails.ignoreTitle // allow updating ignoring title
head = beforeSwapDetails.head // allow updating head algorithm
selectOverride = beforeSwapDetails.selectOverride // allow updating select override

responseInfo.target = target // Make updated target available to response events
Expand Down Expand Up @@ -3447,6 +3447,9 @@ var htmx = (function() {
if (swapSpec.hasOwnProperty('ignoreTitle')) {
ignoreTitle = swapSpec.ignoreTitle
}
if (swapSpec.hasOwnProperty('head')) {
head = swapSpec.head
}

target.classList.add(htmx.config.swappingClass)

Expand Down Expand Up @@ -3524,10 +3527,10 @@ var htmx = (function() {
handleTitle(settleInfo.title);
}

console.log("Here", head)
// merge in new head after swap but before settle
if (triggerEvent(document.body, "htmx:beforeHeadMerge", {head: settleInfo.head})) {
handleHeadTag(settleInfo.head, responseInfo.boosted ? htmx.config.head.boost :
htmx.config.head.other);
handleHeadTag(settleInfo.head, head);
}

if (hasHeader(xhr, /HX-Trigger-After-Swap:/i)) {
Expand Down Expand Up @@ -3642,8 +3645,9 @@ var htmx = (function() {
* @param {import("./htmx").HtmxExtension} extension
*/
function defineExtension(name, extension) {
if (name === "head-support") return; // ignore the head support extension, now integrated into htmx
if (extension.init) {
extension.init(internalAPI)
extension.init(internalAPI);
}
extensions[name] = mergeObjects(extensionBase(), extension)
}
Expand Down
2 changes: 1 addition & 1 deletion test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<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>
<body style="padding:20px;font-family: sans-serif">

Expand Down
9 changes: 9 additions & 0 deletions www/content/attributes/hx-swap.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
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`

You can modify the amount of time that htmx will wait after receiving a response to swap the content
Expand Down
48 changes: 44 additions & 4 deletions www/content/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ custom_classes = "wide-content"
* [confirming](#confirming)
* [inheritance](#inheritance)
* [boosting](#boosting)
* [head tag handling](#head)
* [websockets & SSE](#websockets-and-sse)
* [history](#history)
* [requests & responses](#requests)
Expand Down Expand Up @@ -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
use request parameters.)
* 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:
```html
<button hx-get="/info" hx-on="htmx:beforeRequest: alert('Making a request!')
Expand All @@ -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.
```
* 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
future.
Expand Down Expand Up @@ -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.

### `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}

A feature of `hx-boost` is that it degrades gracefully if javascript is not enabled: the links and forms continue
Expand Down

0 comments on commit 8b59cb9

Please sign in to comment.